码迷,mamicode.com
首页 > 其他好文 > 详细

网络流24题(11/24)

时间:2018-01-29 11:25:46      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:ini   起点   ==   name   需求   click   决定   tchar   问题   

01、飞行员配对方案问题

英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次 派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。


二分图最大匹配

技术分享图片
 1 #include <bits/stdc++.h>
 2 #define min(a, b) ((a) < (b) ? (a) : (b))
 3 using namespace std;
 4 const int MAXN = 100000;
 5 const int INF = 0x3f3f3f3f;
 6 inline void read(int &x)
 7 {
 8     x = 0;char ch = getchar(), c = ch;
 9     while(ch < 0 || ch > 9)c = ch, ch = getchar();
10     while(ch <= 9 && ch >= 0)x = x * 10 + ch - 0, ch = getchar();
11     if(c == -)x = -x; 
12 }
13 
14 struct Edge
15 {
16     int u,v,w,nxt;
17     Edge(int _u, int _v, int _w, int _nxt){u = _u;v = _v;w = _w;nxt = _nxt;}
18     Edge(){}
19 }edge[100010];
20 int head[MAXN<<1],cnt = 1,q[MAXN<<1],h[MAXN<<1],ans=0,n,m,S,T,fa[MAXN <<1];
21 inline void insert(int a,int b,int c)
22 {
23     edge[++cnt] = Edge(a,b,c,head[a]);
24     head[a] = cnt;
25     edge[++cnt] = Edge(b,a,0,head[b]);
26     head[b] = cnt;
27 }
28 bool bfs()
29 {
30     int he = 0, ta = 1;
31     memset(h, -1, sizeof(h));
32     q[he] = S, h[S] = 0;
33     while(he < ta)
34     {
35         int now = q[he ++];
36         for(int pos = head[now];pos;pos = edge[pos].nxt)
37         {
38             int v = edge[pos].v;
39             if(h[v] == -1 && edge[pos].w)
40             {
41                 h[v] = h[now] + 1;
42                 q[ta ++] = v;
43             }
44         }
45     }
46     return h[T] != -1;
47 }
48 
49 int dfs(int x, int f)
50 {
51     if(x == T) return f;
52     int w, used = 0;
53     for(int pos = head[x];pos;pos = edge[pos].nxt)
54     {
55         int v = edge[pos].v;
56         if(h[v] == h[x] + 1)
57         {
58             w = dfs(v, min(f - used, edge[pos].w));
59             if(w) fa[x] = v;
60             edge[pos].w -= w;
61             edge[pos ^ 1].w += w;
62             used += w;
63             if(used == f) return f;
64         }
65     }
66     if(!used) h[x] = -1;
67     return used;
68 }
69 
70 void dinic()
71 {
72     while(bfs()) ans += dfs(S, INF);
73 }
74 
75 int vis[MAXN << 1];
76 
77 int main()
78 {
79     read(m), read(n);
80     int tmp1, tmp2;
81     S = n + m + 2, T = n + m + 3;
82     while(scanf("%d %d", &tmp1, &tmp2) != EOF && tmp1 != -1)
83         insert(tmp1, tmp2, 1);
84     for(register int i = 1;i <= m;++ i)
85         insert(S, i, 1);
86     for(register int i = m + 1;i <= m + n;++ i)
87         insert(i, T, 1);
88     dinic();
89     printf("%d\n", ans);
90     if(ans == 0) printf("No Solution!\n");
91     else
92         for(int i = 1;i <= m;++ i)
93             if(fa[i])
94                 printf("%d %d\n", i, fa[i]);
95     return 0;
96 } 
01

02、太空飞行计划问题

W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业性实验而获取利润。现已确定了一个可供选择的实验集合E= {E1,E2,…,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集RjÍI。配置仪器 Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而 配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。

 

对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。

最大(小)权闭合子图。S连实验,T连仪器,实验与对应仪器连INF,割与S连的边意味着不做这个实验,割与T连的边意味着用这个仪器

于是S集合代表选择的实验和仪器,求最小割,总收益-最小割即为答案

技术分享图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <cmath> 
  9 #define min(a, b) ((a) < (b) ? (a) : (b))
 10 #define max(a, b) ((a) > (b) ? (a) : (b))
 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 12 template <class T>
 13 inline void swap(T& a, T& b)
 14 {
 15     T tmp = a;a = b;b = tmp;
 16 }
 17 inline void read(int &x)
 18 {
 19     x = 0;char ch = getchar(), c = ch;
 20     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 21     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 22     if(c == -) x = -x;
 23 }
 24 
 25 const int INF = 100000;
 26 const int MAXN = 3000 + 10;
 27 const int MAXM = MAXN * MAXN;
 28 
 29 struct Edge
 30 {
 31     int u,v,w,nxt;
 32     Edge(int _u, int _v, int _w, int _nxt){u = _u;v = _v;w = _w;nxt = _nxt;}
 33     Edge(){}
 34 }edge[MAXM << 1];
 35 int head[MAXN], cnt = 1;
 36 inline void insert(int u, int v, int w)
 37 {
 38     edge[++cnt] = Edge(u,v,w,head[u]);
 39     head[u] = cnt;
 40     edge[++cnt] = Edge(v,u,0,head[v]);
 41     head[v] = cnt;
 42 }
 43 
 44 int q[MAXN << 1], h[MAXN << 1], ans, S, T, he, ta;
 45 
 46 bool bfs()
 47 {
 48     int he = 0, ta = 1;
 49     memset(h, -1, sizeof(h));
 50     q[he] = S, h[S] = 0;
 51     while(he < ta)
 52     {
 53         int now = q[he ++];
 54         for(int pos = head[now];pos;pos = edge[pos].nxt)
 55         {
 56             int v = edge[pos].v;
 57             if(h[v] == -1 && edge[pos].w)
 58             {
 59                 h[v] = h[now] + 1;
 60                 q[ta ++] = v;
 61             }
 62         }
 63     }
 64     return h[T] != -1;
 65 }
 66 
 67 int dfs(int x, int f)
 68 {
 69     if(x == T) return f;
 70     int w, used = 0;
 71     for(int pos = head[x];pos;pos = edge[pos].nxt)
 72     {
 73         int v = edge[pos].v;
 74         if(h[v] == h[x] + 1)
 75         {
 76             w = dfs(v, min(f - used, edge[pos].w));
 77             edge[pos].w -= w;
 78             edge[pos ^ 1].w += w;
 79             used += w;
 80             if(used == f) return f;
 81         }
 82     }
 83     if(!used) h[x] = -1;
 84     return used;
 85 }
 86 
 87 void dinic()
 88 {
 89     while(bfs()) ans += dfs(S, INF);
 90 }
 91 
 92 int n,m,sum,vis[MAXN];
 93 
 94 int main()
 95 {
 96     read(m), read(n);S = n + m + 100;T = n + m + 200;
 97     for(int i = 1;i <= m;++ i)
 98     {
 99         char c = 0;int w, tmp = 0;
100         read(w);sum += w;
101         insert(S, i, w);
102         while(c != \n && c != \r)
103         {
104             c = getchar();
105             while(c >= 0 && c <= 9) 
106                 tmp = tmp * 10 + c - 0, c = getchar();
107             if(tmp) insert(i, tmp + m, INF), tmp = 0;
108         }
109     }
110     for(int i = 1;i <= n;++ i)
111     {
112         int tmp;read(tmp);
113         insert(i + m, T, tmp);
114     }
115     dinic();
116     for(int pos = head[S];pos;pos = edge[pos].nxt)
117         if(edge[pos].w)
118             vis[edge[pos].v] = 1;
119     for(int i = 1;i <= m;++ i)    if(h[i] != -1) printf("%d ", i);
120     putchar(\n);
121     for(int i = m + 1;i <= n + m;++ i) if(h[i] != -1) printf("%d ", i - m);putchar(\n);
122     printf("%d", sum - ans);
123     return 0;
124 }
02

03、最小路径覆盖问题

«问题描述:

给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

技术分享图片

每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

«编程任务:

对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

 

 

每个点拆成x,x‘,S->x, x‘->T,对于x->y一条边,连x->y‘。X集合为点x,Y集合为点x‘

正确性:每条路径上的点度数最大为2。x点代表点x的出度,x‘点代表点x的入度。一条边会占用一个点的出度和另一个点的入度。对于每条路径,发现起点只有出度,没有入度,那么Y集合中没有被连的点就是某条路径的起点。于是n - 最大匹配 = 最小路径数

技术分享图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <cmath> 
  9 #define min(a, b) ((a) < (b) ? (a) : (b))
 10 #define max(a, b) ((a) > (b) ? (a) : (b))
 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 12 template <class T>
 13 inline void swap(T& a, T& b)
 14 {
 15     T tmp = a;a = b;b = tmp;
 16 }
 17 inline void read(int &x)
 18 {
 19     x = 0;char ch = getchar(), c = ch;
 20     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 21     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 22     if(c == -) x = -x;
 23 }
 24 
 25 const int INF = 100000;
 26 const int MAXN = 300 + 10;
 27 const int MAXM = MAXN * MAXN;
 28 
 29 struct Edge
 30 {
 31     int u,v,w,nxt;
 32     Edge(int _u, int _v, int _w, int _nxt){u = _u;v = _v;w = _w;nxt = _nxt;}
 33     Edge(){}
 34 }edge[MAXM << 1];
 35 int head[MAXN], cnt = 1;
 36 inline void insert(int u, int v, int w)
 37 {
 38     edge[++cnt] = Edge(u,v,w,head[u]);
 39     head[u] = cnt;
 40     edge[++cnt] = Edge(v,u,0,head[v]);
 41     head[v] = cnt;
 42 }
 43 
 44 int q[MAXN << 1], h[MAXN << 1], ans, S, T, he, ta, fa[MAXN << 1],vis[MAXN];
 45 std::vector<int> node[MAXN << 1]; 
 46 
 47 bool bfs()
 48 {
 49     int he = 0, ta = 1;
 50     memset(h, -1, sizeof(h));
 51     q[he] = S, h[S] = 0;
 52     while(he < ta)
 53     {
 54         int now = q[he ++];
 55         for(int pos = head[now];pos;pos = edge[pos].nxt)
 56         {
 57             int v = edge[pos].v;
 58             if(h[v] == -1 && edge[pos].w)
 59             {
 60                 h[v] = h[now] + 1;
 61                 q[ta ++] = v;
 62             }
 63         }
 64     }
 65     return h[T] != -1;
 66 }
 67 
 68 int dfs(int x, int f)
 69 {
 70     if(x == T) return f;
 71     int w, used = 0;
 72     for(int pos = head[x];pos;pos = edge[pos].nxt)
 73     {
 74         int v = edge[pos].v;
 75         if(h[v] == h[x] + 1)
 76         {
 77             w = dfs(v, min(f - used, edge[pos].w));
 78             if(w) fa[x] = v, node[v].push_back(x);
 79             edge[pos].w -= w;
 80             edge[pos ^ 1].w += w;
 81             used += w;
 82             if(used == f) return f;
 83         }
 84     }
 85     if(!used) h[x] = -1;
 86     return used;
 87 }
 88 
 89 void dinic()
 90 {
 91     while(bfs()) ans += dfs(S, INF);
 92 }
 93 
 94 int n,m; 
 95 
 96 void dfs(int x)
 97 {
 98     vis[x] = 1;
 99     printf("%d ", x);
100     if(fa[x]) dfs(fa[x] - n);
101 }
102 
103 int main()
104 {
105     read(n), read(m);
106     S = n * 2 + 1, T = n * 2 + 2;
107     for(int i = 1;i <= n;++ i) insert(S, i, 1);
108     for(int i = 1;i <= m;++ i)
109     {
110         int tmp1,tmp2;
111         read(tmp1), read(tmp2);
112         insert(tmp1, tmp2 + n, 1);
113     }
114     for(int i = 1;i <= n;++ i) insert(i + n, T, 1);
115     dinic();
116     for(int i = 1;i <= n;++ i)
117         if(fa[i])
118             vis[fa[i] - n] = 1;
119     for(int i = 1;i <= n;++ i)
120         if(!vis[i])
121             dfs(i), putchar(\n);
122     printf("%d", n - ans);
123     return 0;
124 }
03

04、魔术球问题

«问题描述:

假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。

(1)每次只能在某根柱子的最上面放球。

(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。

试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。

«编程任务:

对于给定的n,计算在n根柱子上最多能放多少个球。

 

 

最小路径覆盖变种。二分放多少个球,如果x能放到y上面,就有x->y,答案即为图上的最小路径覆盖数。

发现二分放多少个求,还不如直接从1开始枚举放的求数,每多一个球加一个的边,跑一次增广。

技术分享图片
  1 // luogu-judger-enable-o2
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <algorithm>
  7 #include <queue>
  8 #include <vector>
  9 #include <cmath> 
 10 #define min(a, b) ((a) < (b) ? (a) : (b))
 11 #define max(a, b) ((a) > (b) ? (a) : (b))
 12 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 13 template <class T>
 14 inline void swap(T& a, T& b)
 15 {
 16     T tmp = a;a = b;b = tmp;
 17 }
 18 inline void read(int &x)
 19 {
 20     x = 0;char ch = getchar(), c = ch;
 21     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 22     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 23     if(c == -) x = -x;
 24 }
 25 
 26 const int INF = 100000;
 27 const int MAXN = 100000;
 28 const int MAXM = 100000;
 29 
 30 struct Edge
 31 {
 32     int u,v,w,nxt;
 33     Edge(int _u, int _v, int _w, int _nxt){u = _u;v = _v;w = _w;nxt = _nxt;}
 34     Edge(){}
 35 }edge[MAXM << 1];
 36 int head[MAXN << 1], cnt = 1, S, T, ans, fa[MAXN << 1], h[MAXN << 1], q[MAXN << 1], he, ta;
 37 inline void insert(int a, int b, int c)
 38 {
 39     edge[++cnt] = Edge(a,b,c,head[a]);
 40     head[a] = cnt;
 41     edge[++cnt] = Edge(b,a,0,head[b]);
 42     head[b] = cnt;
 43 }
 44 bool bfs()
 45 {
 46     memset(h, -1, sizeof(h));
 47     he = 0, ta = 1, q[0] = S, h[S] = 0;
 48     while(he < ta)
 49     {
 50         int now = q[he ++];
 51         for(int pos = head[now];pos;pos = edge[pos].nxt)
 52         {
 53             int v = edge[pos].v;
 54             if(h[v] == -1 && edge[pos].w) q[ta ++] = v, h[v] = h[now] + 1;
 55         }
 56     }
 57     return h[T] != -1;
 58 }
 59 int dfs(int x, int f)
 60 {
 61     if(x == T) return f; 
 62     int used = 0, w;
 63     for(int pos = head[x];pos;pos = edge[pos].nxt)
 64     {
 65         int v = edge[pos].v;
 66         if(h[v] == h[x] + 1)
 67         {
 68             w = dfs(v, min(f - used, edge[pos].w));
 69             if(w) fa[x] = v;
 70             edge[pos].w -= w;
 71             edge[pos ^ 1].w += w;
 72             used += w;
 73             if(used == f) return f;
 74         }
 75     }
 76     if(!used) h[x] = -1;
 77     return used;
 78 }
 79 void Dinic()
 80 {
 81     while(bfs()) ans += dfs(S, INF);
 82 }
 83 
 84 int n, ma, vis[MAXN]; 
 85 
 86 void dfs(int x)
 87 {
 88     vis[x] = 1;
 89     printf("%d ", x);
 90     if(fa[x]) dfs(fa[x] - 2000);
 91 }
 92 
 93 int main()
 94 {
 95     read(n);S = 10000, T = S + 1;
 96     for(ma = 1;;++ ma)
 97     {
 98         insert(S, ma, 1); insert(ma + 2000, T, 1);
 99         for(int j = sqrt(ma) + 1;j * j - ma < ma;++ j)
100             insert(j * j - ma, ma + 2000, 1);
101         Dinic();
102         if(ma - ans == n + 1) break;
103     }
104     -- ma;
105     printf("%d\n", ma);
106     memset(head, 0, sizeof(head)), cnt = 0, memset(fa, 0, sizeof(fa)), ans = 0;
107     for(int i = 1;i <= ma;++ i)
108     {
109         insert(S, i, 1); insert(i + 2000, T, 1);
110         int t = sqrt(i); 
111         for(int j = sqrt(i) + 1;j * j - i < i;++ j)
112             insert(j * j - i, i + 2000, 1);
113         Dinic();
114     }
115     for(int i = 1;i <= ma;++ i)
116         if(fa[i]) vis[fa[i] - 2000] = 1;
117     for(int i = 1;i <= ma;++ i)    if(!vis[i]) dfs(i), putchar(\n);
118     return 0;
119 }
04

 

05、圆桌问题

假设有来自m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为ri (i =1,2,……,m)。

会议餐厅共有n 张餐桌,每张餐桌可容纳ci (i =1,2,……,n)个代表就餐。

为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法,给出满足要求的代表就餐方案。

对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。

 

有点裸

技术分享图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <cmath> 
  9 #define min(a, b) ((a) < (b) ? (a) : (b))
 10 #define max(a, b) ((a) > (b) ? (a) : (b))
 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 12 template <class T>
 13 inline void swap(T& a, T& b)
 14 {
 15     T tmp = a;a = b;b = tmp;
 16 }
 17 inline void read(int &x)
 18 {
 19     x = 0;char ch = getchar(), c = ch;
 20     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 21     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 22     if(c == -) x = -x;
 23 }
 24 
 25 const int INF = 100000;
 26 const int MAXN = 10000;
 27 const int MAXM = 100000;
 28 
 29 struct Edge
 30 {
 31     int u,v,w,nxt;
 32     Edge(int _u, int _v, int _w, int _nxt){u = _u;v = _v;w = _w;nxt = _nxt;}
 33     Edge(){}
 34 }edge[MAXM << 1];
 35 int head[MAXN << 1], cnt = 1, S, T, ans, h[MAXN << 1], q[MAXN << 1], he, ta;
 36 inline void insert(int a, int b, int c)
 37 {
 38     edge[++cnt] = Edge(a,b,c,head[a]);
 39     head[a] = cnt;
 40     edge[++cnt] = Edge(b,a,0,head[b]);
 41     head[b] = cnt;
 42 }
 43 bool bfs()
 44 {
 45     memset(h, -1, sizeof(h));
 46     he = 0, ta = 1, q[0] = S, h[S] = 0;
 47     while(he < ta)
 48     {
 49         int now = q[he ++];
 50         for(int pos = head[now];pos;pos = edge[pos].nxt)
 51         {
 52             int v = edge[pos].v;
 53             if(h[v] == -1 && edge[pos].w)
 54             {
 55                 q[ta ++] = v, h[v] = h[now] + 1;
 56             }
 57         }
 58     }
 59     return h[T] != -1;
 60 }
 61 int dfs(int x, int f)
 62 {
 63     if(x == T) return f; 
 64     int used = 0, w;
 65     for(int pos = head[x];pos;pos = edge[pos].nxt)
 66     {
 67         int v = edge[pos].v;
 68         if(h[v] == h[x] + 1)
 69         {
 70             w = dfs(v, min(f - used, edge[pos].w));
 71             edge[pos].w -= w;
 72             edge[pos ^ 1].w += w;
 73             used += w;
 74             if(used == f) return f;
 75         }
 76     }
 77     if(!used) h[x] = -1;
 78     return used;
 79 }
 80 void Dinic()
 81 {
 82     while(bfs()) ans += dfs(S, INF);
 83 }
 84 int n,m,tmp,sum,vis[MAXN];
 85 
 86 int main()
 87 {
 88     read(m), read(n); S = n + m + 1, T = S + 1;
 89     for(int i = 1;i <= m;++ i) read(tmp), sum += tmp, insert(S, i, tmp);
 90     for(int i = 1;i <= n;++ i) read(tmp), insert(i + m, T, tmp);
 91     for(int i = 1;i <= m;++ i)
 92         for(int j = 1;j <= n;++ j)
 93             insert(i, j + m, 1);
 94     Dinic();
 95     if(ans != sum){printf("0\n");return 0;}
 96     printf("1");
 97     for(int i = 1;i <= m;++ i)
 98     {
 99         int flag = 1;
100         for(int pos = head[i];pos;pos = edge[pos].nxt)
101             if(edge[pos].v == S) continue;
102             else if(!edge[pos].w)
103                 if(flag) printf("\n%d ", edge[pos].v - m), flag = 0;
104                 else printf("%d ", edge[pos].v - m); 
105     }
106     return 0;
107 }
05

 

06、最长不下降子序列问题

«问题描述:

给定正整数序列x1,...,xn 。

(1)计算其最长不下降子序列的长度s。

(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。

(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。

«编程任务:

设计有效算法完成(1)(2)(3)提出的计算任务。

 

第一、二个问题都有nlogn解法,详见http://www.cnblogs.com/huibixiaoxing/p/7398826.html第三题

这里讨论网络流解法

第一问直接暴力dp即可,设答案为k

第二问,相当于每个点限流1,用最大流模拟转移,考虑拆点。对于点x,拆成x和x‘,x - > x‘,容量1, 对于i和j,i < j,若有s[j] >= s[i],就从i’ - > j,容量为1。对于f[i] = k的点i,连i‘ - > T,容量为1,可以证明每一个序列都可以通过一个流表示出来。跑最大流即可

第三问,相当于x1和xn可以取无数次,那就把x1->x1‘,xn->xn‘,S->x1‘,S->xn‘,xn‘->T(如果存在),x1‘->T(如果存在)改成正无穷即可

技术分享图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <cmath> 
  9 #define min(a, b) ((a) < (b) ? (a) : (b))
 10 #define max(a, b) ((a) > (b) ? (a) : (b))
 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 12 template <class T>
 13 inline void swap(T& a, T& b)
 14 {
 15     T tmp = a;a = b;b = tmp;
 16 }
 17 inline void read(int &x)
 18 {
 19     x = 0;char ch = getchar(), c = ch;
 20     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 21     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 22     if(c == -) x = -x;
 23 }
 24 
 25 const int INF = 100000;
 26 const int MAXN = 10000;
 27 const int MAXM = 100000;
 28 
 29 struct Edge
 30 {
 31     int u,v,w,nxt;
 32     Edge(int _u, int _v, int _w, int _nxt){u = _u;v = _v;w = _w;nxt = _nxt;}
 33     Edge(){}
 34 }edge[MAXM << 1];
 35 int head[MAXN << 1], cnt = 1, S, T, ans, h[MAXN << 1], q[MAXN << 1], he, ta;
 36 inline void insert(int a, int b, int c)
 37 {
 38     edge[++cnt] = Edge(a,b,c,head[a]);
 39     head[a] = cnt;
 40     edge[++cnt] = Edge(b,a,0,head[b]);
 41     head[b] = cnt;
 42 }
 43 bool bfs()
 44 {
 45     memset(h, -1, sizeof(h));
 46     he = 0, ta = 1, q[0] = S, h[S] = 0;
 47     while(he < ta)
 48     {
 49         int now = q[he ++];
 50         for(int pos = head[now];pos;pos = edge[pos].nxt)
 51         {
 52             int v = edge[pos].v;
 53             if(h[v] == -1 && edge[pos].w)
 54             {
 55                 q[ta ++] = v, h[v] = h[now] + 1;
 56             }
 57         }
 58     }
 59     return h[T] != -1;
 60 }
 61 int dfs(int x, int f)
 62 {
 63     if(x == T) return f; 
 64     int used = 0, w;
 65     for(int pos = head[x];pos;pos = edge[pos].nxt)
 66     {
 67         int v = edge[pos].v;
 68         if(h[v] == h[x] + 1)
 69         {
 70             w = dfs(v, min(f - used, edge[pos].w));
 71             edge[pos].w -= w;
 72             edge[pos ^ 1].w += w;
 73             used += w;
 74             if(used == f) return f;
 75         }
 76     }
 77     if(!used) h[x] = -1;
 78     return used;
 79 }
 80 void Dinic()
 81 {
 82     while(bfs()) ans += dfs(S, INF);
 83 }
 84 
 85 int n, f[MAXN], num[MAXN], ma;
 86 
 87 int main()
 88 {
 89     read(n);
 90     for(register int i = 1;i <= n;++ i)
 91     {
 92         insert(i, i + n, 1);
 93         read(num[i]);
 94         f[i] = 1;
 95         for(register int j = 1;j < i;++ j)
 96             if(num[j] <= num[i]) f[i] = max(f[i], f[j] + 1);
 97         ma = max(ma, f[i]);
 98     }
 99     printf("%d\n", ma);
100     if(ma == 1)
101     {
102         printf("%d\n%d", n, n);
103         return 0;
104     } 
105     S = n + n + 1, T = S + 1; 
106     for(register int i = 1;i <= n;++ i) 
107         if(f[i] == 1) insert(S, i, 1); 
108         else if(f[i] == ma) insert(i + n, T, 1);
109     for(register int i = 1;i <= n;++ i)
110         for(register int j = 1;j < i;++ j)
111             if(num[j] <= num[i] && f[i] == f[j] + 1)
112                 insert(j + n, i, 1);
113     Dinic();
114     printf("%d\n", ans);
115     insert(1, n + 1, INF), insert(n, n + n, INF);
116     if(f[1] == 1) insert(S, 1, INF);
117     if(f[1] == ma) insert(1 + n, T, INF);
118     if(f[n] == 1) insert(S, n, INF);
119     if(f[n] == ma) insert(n + n, T, INF);
120     Dinic();
121     printf("%d", ans); 
122     return 0;
123 }
06

 

07、试题库问题

«问题描述:

假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。

«编程任务:

对于给定的组卷要求,计算满足要求的组卷方案。

 

有点裸

技术分享图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <cmath> 
  9 #define min(a, b) ((a) < (b) ? (a) : (b))
 10 #define max(a, b) ((a) > (b) ? (a) : (b))
 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 12 template <class T>
 13 inline void swap(T& a, T& b)
 14 {
 15     T tmp = a;a = b;b = tmp;
 16 }
 17 inline void read(int &x)
 18 {
 19     x = 0;char ch = getchar(), c = ch;
 20     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 21     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 22     if(c == -) x = -x;
 23 }
 24 
 25 const int INF = 100000;
 26 const int MAXN = 100000 + 10;
 27 const int MAXM = 1000000 + 10;
 28 
 29 struct Edge
 30 {
 31     int u,v,w,nxt;
 32     Edge(int _u, int _v, int _w, int _nxt){u = _u;v = _v;w = _w;nxt = _nxt;}
 33     Edge(){}
 34 }edge[MAXM << 1];
 35 int head[MAXN << 1], cnt = 1, S, T, ans, h[MAXN << 1], fa[MAXN << 1], q[MAXN << 1], he, ta;
 36 inline void insert(int a, int b, int c)
 37 {
 38     edge[++ cnt] = Edge(a,b,c,head[a]);
 39     head[a] = cnt;
 40     edge[++ cnt] = Edge(b,a,0,head[b]);
 41     head[b] = cnt;
 42 }
 43 bool bfs()
 44 {
 45     he = 0, ta = 1, q[he] = S, memset(h, -1, sizeof(h)), h[S] = 0;
 46     while(he < ta)
 47     {
 48         int now = q[he ++];
 49         for(int pos = head[now];pos;pos = edge[pos].nxt)
 50         {
 51             int v = edge[pos].v;
 52             if(h[v] == -1 && edge[pos].w)
 53                 h[v] = h[now] + 1, q[ta ++] = v;
 54         }
 55     }
 56     return h[T] != -1;
 57 }
 58 int dfs(int x, int f)
 59 {
 60     if(x == T) return f;
 61     int w,used = 0;
 62     for(int pos = head[x];pos;pos = edge[pos].nxt)
 63     {
 64         int v = edge[pos].v;
 65         if(h[v] == h[x] + 1)
 66         {
 67             w = dfs(v, min(f - used, edge[pos].w));
 68             edge[pos].w -= w;
 69             edge[pos ^ 1].w += w;
 70             if(w) fa[x] = v;
 71             used += w;
 72             if(used == f) return f;
 73         }
 74     }
 75     if(!used) h[x] = -1;
 76     return used;
 77 }
 78 void Dinic()
 79 {
 80     while(bfs()) ans += dfs(S, INF);
 81 }
 82 int k,n,tmp,tmp2,sum;
 83 int main()
 84 {
 85     read(k), read(n);
 86     S = n + k + 1, T = S + 1;
 87     for(int i = 1;i <= n;++ i) insert(S, i, 1);
 88     for(int i = 1;i <= k;++ i) read(tmp), sum += tmp, insert(n + i, T, tmp);
 89     for(int i = 1;i <= n;++ i)
 90     {
 91         read(tmp);
 92         for(int j = 1;j <= tmp;++ j) read(tmp2), insert(i, tmp2 + n, 1);
 93     }
 94     Dinic();
 95     if(ans != sum){printf("No Solution!\n");return 0;}
 96     for(int i = 1;i <= k;++ i) 
 97     {
 98         printf("%d: ", i);
 99         for(int j = 1;j <= n;++ j) if(fa[j] == i + n) printf("%d ", j);
100         putchar(\n);
101     }
102     return 0;
103 }
07

08、机器人路径规划问题

机器人 Rob 可在一个树状路径上自由移动。给定树状路径 T 上的起点 s 和终点 t,机器人 Rob 要从 s 运动到 t。树状路径 T 上有若干可移动的障碍物。由于路径狭窄,任何时刻在路径的任何位置不能同时容纳 2 个物体。每一步可以将障碍物或机器人移到相邻的空顶点上。设计一个有效算法用最少移动次数使机器人从 s 运动到 t。对于给定的树 T,以及障碍物在树 T 中的分布情况。计算机器人从起点 s 到终点 t 的最少移动次数。

 

据说此题网络流不可做。其他做法也不太好,复杂度很高网络流24题:我们之中出了个叛徒!

 

09、方格取数问题

在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

 

看见方格就黑白染色。发现不能放在相邻的异色格子上。想到最小割。

对于白色格点(i,j),向黑色格点(i + 1, j)和(i,j + 1)连边,容量INF,S向白色格点连权值,黑色格点向T连权值,每一条S->T的路径都对应一个不满足条件的放法,因此要使得取出的数S->T不存在,割掉一条边意味着不取出这个方格中的数,求最小割即为留下的最少,取出的用总和减

技术分享图片
  1 // luogu-judger-enable-o2
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <algorithm>
  7 #include <queue>
  8 #include <vector>
  9 #include <cmath> 
 10 #define min(a, b) ((a) < (b) ? (a) : (b))
 11 #define max(a, b) ((a) > (b) ? (a) : (b))
 12 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 13 #define hao(a, b) ((a) * m + (b)) 
 14 template <class T>
 15 inline void swap(T& a, T& b)
 16 {
 17     T tmp = a;a = b;b = tmp;
 18 }
 19 inline void read(int &x)
 20 {
 21     x = 0;char ch = getchar(), c = ch;
 22     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 23     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 24     if(c == -) x = -x;
 25 }
 26 
 27 const int INF = 100000;
 28 const int MAXN = 100000 + 10;
 29 const int MAXM = 1000000 + 10;
 30 
 31 struct Edge
 32 {
 33     int u,v,w,nxt;
 34     Edge(int _u, int _v, int _w, int _nxt){u = _u, v = _v, w = _w, nxt = _nxt;}
 35     Edge(){}
 36 }edge[MAXM << 1];
 37 int head[MAXN << 1], cnt = 1, q[MAXN << 1], h[MAXN << 1], S, T, ans, he, ta;
 38 inline void insert(int a, int b, int c)
 39 {
 40     edge[++cnt] = Edge(a,b,c,head[a]);
 41     head[a] = cnt;
 42     edge[++cnt] = Edge(b,a,0,head[b]);
 43     head[b] = cnt;
 44 }
 45 bool bfs()
 46 {
 47     memset(h, -1, sizeof(h)), he = 0, ta = 1, q[0] = S, h[S] = 0;
 48     while(he < ta)
 49     {
 50         int now = q[he ++];
 51         for(int pos = head[now];pos;pos = edge[pos].nxt)
 52         {
 53             int v = edge[pos].v;
 54             if(h[v] == -1 && edge[pos].w)
 55                 h[v] = h[now] + 1, q[ta ++] = v;
 56         }
 57     }
 58     return h[T] != -1;
 59 }
 60 int dfs(int x, int f)
 61 {
 62     if(x == T) return f;
 63     int used = 0, w;
 64     for(int pos = head[x];pos;pos = edge[pos].nxt)
 65     {
 66         int v = edge[pos].v;
 67         if(h[v] == h[x] + 1)
 68         {
 69             w = dfs(v, min(f - used, edge[pos].w));
 70             edge[pos].w -= w;
 71             edge[pos ^ 1].w += w;
 72             used += w;
 73             if(used == f) return f; 
 74         }
 75     }
 76     if(!used) h[x] = -1;
 77     return used;
 78 }
 79 void Dinic()
 80 {
 81     while(bfs()) ans += dfs(S, INF);
 82 }
 83 
 84 int n,m,g[150][150],sum;
 85 
 86 int main()
 87 {
 88     read(n), read(m);
 89     S = hao(n, m) + 1, T = S + 1;
 90     for(int i = 1;i <= n;++ i) 
 91         for(int j = 1;j <= m;++ j) 
 92         {
 93             int tmp; read(tmp);sum += tmp;
 94             if((i + j) & 1) 
 95             {
 96                 insert(S, hao(i, j), tmp);
 97                 if(i + 1 <= n) insert(hao(i, j), hao(i + 1, j), INF);
 98                 if(j + 1 <= m) insert(hao(i, j), hao(i, j + 1), INF);
 99             }
100             else 
101             {
102                 insert(hao(i, j), T, tmp);
103                 if(i + 1 <= n) insert(hao(i + 1, j), hao(i, j), INF);
104                 if(j + 1 <= m) insert(hao(i, j + 1), hao(i, j), INF);
105             }
106         }
107     Dinic();
108     printf("%d", sum - ans);
109     return 0;
110 }
09

 

10、餐巾计划问题

一个餐厅在相继的 NNN 天里,每天需用的餐巾数不尽相同。假设第 iii 天需要 rir_iri?块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 ppp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nnn 天(n>mn>mn>m),其费用为 sss 分(s<fs<fs<f)。

每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。

试设计一个算法为餐厅合理地安排好 NNN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。

 

每天拆成两个点x(X集合),x(Y集合)‘,x表示第x天用完剩下的餐巾,x‘表示第x天要用的餐巾,让x‘连向T,容量为当天需要的餐巾数,把S连向x,容量为当天需要的餐巾数,考虑如何用X集合补满Y集合的流。

对于购买,从S连向Y集合,容量+∞,费用p

对于快洗,x->x + m,容量+∞,费用f

对于慢洗,x->x + nnn,容量+∞,费用sss

还有可能上一天的餐巾留到下一天,从x -> x + 1容量+∞,费用0(容易漏掉)

 

技术分享图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <cmath> 
  9 #define min(a, b) ((a) < (b) ? (a) : (b))
 10 #define max(a, b) ((a) > (b) ? (a) : (b))
 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 12 template <class T>
 13 inline void swap(T& a, T& b)
 14 {
 15     T tmp = a;a = b;b = tmp;
 16 }
 17 inline void read(long long &x)
 18 {
 19     x = 0;char ch = getchar(), c = ch;
 20     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 21     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 22     if(c == -) x = -x;
 23 }
 24 
 25 const long long INF = 0x3f3f3f3f3f3f3f3f;
 26 const long long MAXN = 200000 + 10;
 27 const long long MAXM = 1000000 + 10;
 28 
 29 struct Edge
 30 {
 31     long long u,v,w,c,nxt;
 32     Edge(long long _u, long long _v, long long _w, long long _c, long long _nxt){u = _u;v = _v;w = _w;c = _c;nxt = _nxt;}
 33     Edge(){}
 34 }edge[MAXN << 1];
 35 long long head[MAXN << 1], cnt = 1, q[MAXN << 1], he, ta, d[MAXN << 1], b[MAXN << 1], from[MAXN << 1], S, T, ans, nn;
 36 inline void insert(long long a, long long b, long long c, long long d)
 37 {
 38     edge[++cnt] = Edge(a,b,c,d,head[a]);
 39     head[a] = cnt;
 40     edge[++cnt] = Edge(b,a,0,-d,head[b]);
 41     head[b] = cnt;
 42 }
 43 bool bfs()
 44 {
 45     he = 0, ta = 1, memset(d, 0x3f3f3f3f, sizeof(d)), d[S] = 0, b[S] = 1, q[0] = S;
 46     while(he < ta)
 47     {
 48         long long now = q[he ++];
 49         if(he > MAXN) he = 0; 
 50         for(long long pos = head[now];pos;pos = edge[pos].nxt)
 51         {
 52             long long v = edge[pos].v;
 53             if(edge[pos].w && d[v] > d[now] + edge[pos].c)
 54             {
 55                 d[v] = d[now] + edge[pos].c, from[v] = pos;
 56                 if(!b[v])
 57                 {
 58                     b[v] = 1, q[ta ++] = v;
 59                     if(ta > MAXN) ta = 0;
 60                 }
 61             }
 62         }
 63         b[now] = 0;
 64     }
 65     return d[T] != INF;
 66 }
 67 void flow()
 68 {
 69     long long x = INF;
 70     for(long long i = from[T];i;i = from[edge[i].u]) x = min(x, edge[i].w);
 71     for(long long i = from[T];i;i = from[edge[i].u]) edge[i].w -= x, edge[i ^ 1].w += x, ans += edge[i].c * x;
 72 }
 73 void mcf()
 74 {
 75     while(bfs()) 
 76         flow();
 77 }
 78 
 79 long long num[MAXN],p,m,f,n,s;
 80 
 81 int main()
 82 {
 83     read(nn);S = nn + nn + 1, T = S + 1;
 84      for(long long i = 1;i <= nn;++ i) read(num[i]);
 85     read(p), read(m), read(f), read(n), read(s);
 86     for(long long i = 1;i <= nn;++ i) 
 87         insert(S, i, num[i], 0);
 88     for(long long i = 1;i < nn;++ i)  
 89         insert(i, i + 1, INF, 0);
 90     for(long long i = 1;i <= nn - m;++ i) 
 91         insert(i, i + m + nn, INF, f);
 92     for(long long i = 1;i <= nn - n;++ i) 
 93         insert(i, i + n + nn, INF, s);
 94     for(long long i = 1;i <= nn;++ i) 
 95         insert(S, i + nn, INF, p);
 96     for(long long i = 1;i <= nn;++ i) 
 97         insert(i + nn, T, num[i], 0);
 98     mcf();
 99     printf("%lld", ans);
100     
101     return 0;
102 }
10

 

11、航空路线问题

 

给定一张航空图,图中顶点代表城市,边代表 2 城市间的直通航线。现要求找出一条满足下述限制条件的且途经城市最多的旅行路线。

(1)从最西端城市出发,单向从西向东途经若干城市到达最东端城市,然后再单向从东向西飞回起点(可途经若干城市)。

(2)除起点城市外,任何城市只能访问 1 次。

对于给定的航空图,试设计一个算法找出一条满足要求的最佳航空旅行路线。

 

直接想成从起点到终点,找两条不相交最路径即可

每个点限流一次,还是考虑拆点x,x‘,x - > x‘容量为1,费用为0,特别的起点和终点可以流两次,S - S‘和T - > T‘,容量为2,费用为0

对于a -> b,连a‘ -> b,容量为1,费用为1(环上点数等于边数)

求最大费用最大流即可

技术分享图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <map>
  9 #include <string> 
 10 #include <cmath> 
 11 #define min(a, b) ((a) < (b) ? (a) : (b))
 12 #define max(a, b) ((a) > (b) ? (a) : (b))
 13 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
 14 template <class T>
 15 inline void swap(T& a, T& b)
 16 {
 17     T tmp = a;a = b;b = tmp;
 18 }
 19 inline void read(int &x)
 20 {
 21     x = 0;char ch = getchar(), c = ch;
 22     while(ch < 0 || ch > 9) c = ch, ch = getchar();
 23     while(ch <= 9 && ch >= 0) x = x * 10 + ch - 0, ch = getchar();
 24     if(c == -) x = -x;
 25 }
 26 
 27 const int INF = 0x3f3f3f3f;
 28 const int MAXN = 100000 + 10;
 29 const int MAXM = 1000000 + 10;
 30 
 31 struct Edge
 32 {
 33     int u,v,w,c,nxt;
 34     Edge(int _u, int _v, int _w, int _c, int _nxt){u = _u;v = _v;w = _w;c = _c;nxt = _nxt;}
 35     Edge(){}
 36 }edge[MAXM << 1];
 37 int head[MAXN << 1], he, ta, cnt = 1, ans, anss, q[MAXN << 1], from[MAXN << 1], d[MAXN << 1], b[MAXN << 1], S, T;
 38 void insert(int a, int b, int c, int d)
 39 {
 40     edge[++cnt] = Edge(a,b,c,d,head[a]); head[a] = cnt;
 41     edge[++cnt] = Edge(b,a,0,-d,head[b]); head[b] = cnt;
 42 }
 43 bool spfa()
 44 {
 45     memset(d, 0x3f, sizeof(d));
 46     int he = 0, ta = 1;
 47     d[S] = 0, b[S] = 1, q[he] = S;
 48     while(he != ta)
 49     {
 50         int now = q[he ++];
 51         if(he > MAXN) he = 0;
 52         for(int pos = head[now];pos;pos = edge[pos].nxt)
 53             if(edge[pos].w && d[edge[pos].v] > d[now] + edge[pos].c)
 54             {
 55                 d[edge[pos].v] = d[now] + edge[pos].c;
 56                 from[edge[pos].v] = pos;
 57                 if(!b[edge[pos].v])
 58                 {
 59                     b[edge[pos].v]=1;
 60                     q[ta ++] = edge[pos].v;
 61                     if(ta > MAXN)ta = 0;
 62                 } 
 63             }
 64         b[now] = 0; 
 65     }
 66     if(d[T] == INF)return 0;
 67     return 1;
 68 }
 69 
 70 void flow()
 71 {
 72     int x = INF;
 73     for(int i = from[T];i;i = from[edge[i].u])
 74         x = min(x, edge[i].w);
 75     for(int i = from[T];i;i = from[edge[i].u])
 76     {
 77         edge[i].w -= x;
 78         edge[i^1].w += x;
 79         ans += edge[i].c * x;
 80     }
 81     anss += x;
 82 }
 83 
 84 void mcf()
 85 {
 86     while(spfa()) flow();
 87 }
 88 
 89 int n,m,vis[MAXN];
 90 std::string s[MAXN];
 91 std::map<std::string, int> mp;
 92 
 93 void dfs(int x)
 94 {
 95     if(x == n) return;
 96     vis[x] = 1;
 97     std::cout << s[x] << std::endl;
 98     x += n;
 99     for(int pos = head[x];pos;pos = edge[pos].nxt)
100     {
101         int v = edge[pos].v;
102         if(v > n || vis[v] || edge[pos].w) continue;
103         dfs(v);return;
104     }
105 }
106 void redfs(int x)
107 {
108     vis[x] = 1;
109     if(x == n)
110     {
111         std::cout << s[n] << std::endl;
112         return;
113     }
114     x += n;
115     for(int pos = head[x];pos;pos = edge[pos].nxt)
116     {
117         int v = edge[pos].v;
118         if(v > n || vis[v] || edge[pos].w) continue;
119         redfs(v);break;
120     }
121     std::cout << s[x - n] << std::endl;
122 }
123 
124 int main()
125 {
126     read(n), read(m);S = 1, T = n + n;
127     for(int i = 1;i <= n;++ i)
128     {
129         std::cin >> s[i];
130         mp[s[i]] = i;
131     }
132     insert(1, 1 + n, 2, 0);
133     insert(n, n + n, 2, 0);
134     for(int i = 2;i < n;++ i) 
135         insert(i, i + n, 1, 0);
136     for(int i = 1;i <= m;++ i)
137     {
138         std::string tmp1,tmp2;
139         std::cin >> tmp1 >> tmp2;
140         int ma1, ma2;
141         ma1 = mp[tmp1], ma2 = mp[tmp2];
142         if(ma1 > ma2) swap(ma1, ma2);
143         if(ma1 == 1 && ma2 == n) insert(ma1 + n, ma2, 2, -1);
144         else insert(ma1 + n, ma2, 1, -1);
145     }
146     mcf();
147     if(anss != 2) printf("No Solution!\n");
148     else 
149     {
150         printf("%d\n", -ans);
151         dfs(1);
152         redfs(1);
153     }
154     return 0;
155 }
11

 

(未完待续.....)

 

网络流24题(11/24)

标签:ini   起点   ==   name   需求   click   决定   tchar   问题   

原文地址:https://www.cnblogs.com/huibixiaoxing/p/8372631.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!