专题链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=68128#overview
网络流基础知识:http://www.cnblogs.com/yaoyueduzhen/p/5020722.html
本专题考察网络流问题, 包含最大流和最小费用最大流,请使用高效模板。
A. poj3436 ACM Computer Factory
分析:这个是一个网络流,对流过每个点的流量有限制,这样就需要拆点,把每个结点拆成两个,一个入点,一个出点,并从入点到出点连接一条边流量为点的的流向限制,把所有接入该点的边接入它的入点,从该点流出的边从出点流出。
建图方法,每个机器是一个点,把源与所有没有必须元件的点连接,所有完整元件的点与汇连接,若一台机器的输出能符合另一台机器的输入条件则连一条边。把每个机器拆点,其内部边流量为其生产速度。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN=120; 8 const int MAXM=120*120; 9 const int INF=0x3f3f3f3f; 10 int p,n; 11 int q[MAXN]; 12 int in[MAXN][MAXN],out[MAXN][MAXN]; 13 14 struct Edge 15 { 16 int to, next, cap, flow; 17 }edge[MAXM]; 18 int tol; 19 int head[MAXN]; 20 void init() 21 { 22 tol = 2; 23 memset(head, -1, sizeof(head)); 24 } 25 void addedge(int u, int v, int w, int rw=0) 26 { 27 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 28 edge[tol].next = head[u]; head[u] = tol++; 29 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 30 edge[tol].next = head[v]; head[v] = tol++; 31 } 32 int Q[MAXN]; 33 int dep[MAXN], cur[MAXN], sta[MAXN]; 34 bool bfs(int s, int t, int n) 35 { 36 int front = 0, tail = 0; 37 memset(dep, -1, sizeof(dep)); 38 dep[s] = 0; 39 Q[tail++] = s; 40 while(front < tail) 41 { 42 int u = Q[front++]; 43 for(int i = head[u]; i != -1; i = edge[i].next) 44 { 45 int v = edge[i].to; 46 if(edge[i].cap > edge[i].flow && dep[v] == -1) 47 { 48 dep[v] = dep[u] + 1; 49 if(v == t) return true; 50 Q[tail++] = v; 51 } 52 } 53 } 54 return false; 55 } 56 57 int dinic(int s, int t, int n) 58 { 59 int maxflow = 0; 60 while(bfs(s, t, n)) 61 { 62 for(int i = 0; i < n; i++) cur[i] = head[i]; 63 int u = s, tail = 0; 64 while(cur[s] != -1) 65 { 66 if(u == t) 67 { 68 int tp = INF; 69 for(int i = tail-1; i >= 0; i--) 70 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 71 maxflow+=tp; 72 for(int i = tail-1; i >= 0; i--) 73 { 74 edge[sta[i]].flow+=tp; 75 edge[sta[i]^1].flow-=tp; 76 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 77 tail = i; 78 } 79 u = edge[sta[tail]^1].to; 80 } 81 else 82 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 83 { 84 sta[tail++] = cur[u]; 85 u = edge[cur[u]].to; 86 } 87 else 88 { 89 while(u != s && cur[u] == -1) 90 u = edge[sta[--tail]^1].to; 91 cur[u] = edge[cur[u]].next; 92 } 93 } 94 } 95 return maxflow; 96 } 97 98 int main() 99 { 100 scanf("%d%d",&p,&n); 101 init(); 102 for(int i=1;i<=n;++i) 103 { 104 scanf("%d",&q[i]); 105 for(int j=1;j<=p;++j) 106 scanf("%d",&in[i][j]); 107 for(int j=1;j<=p;++j) 108 scanf("%d",&out[i][j]); 109 } 110 for(int i=1;i<=n;++i) 111 addedge(i,n+i,q[i]); 112 for(int i=1;i<=n;++i) 113 for(int j=1;j<=n;++j) 114 if(i!=j) 115 { 116 bool flag=true; 117 for(int k=1;k<=p;++k) 118 { 119 if(out[i][k]==0&&in[j][k]==1) 120 { 121 flag=false; 122 break; 123 } 124 if(out[i][k]==1&&in[j][k]==0) 125 { 126 flag=false; 127 break; 128 } 129 } 130 if(flag) 131 addedge(i+n,j,min(q[i],q[j])); 132 } 133 for(int i=1;i<=n;++i) 134 { 135 bool f=true; 136 for(int j=1;j<=p;++j) 137 { 138 if(in[i][j]==1) 139 { 140 f=false; 141 break; 142 } 143 } 144 if(f) addedge(0,i,q[i]); 145 } 146 for(int i=1;i<=n;++i) 147 { 148 bool f=true; 149 for(int j=1;j<=p;++j) 150 { 151 if(out[i][j]==0) 152 { 153 f=false; 154 break; 155 } 156 } 157 if(f) 158 addedge(i+n,2*n+1,q[i]); 159 } 160 int res=dinic(0,2*n+1,2*n+2); 161 int count=0; 162 for(int i=1;i<=n;++i) 163 for(int j=head[i+n];j!=-1;j=edge[j].next) 164 if(edge[j].to!=2*n+1&&edge[j].flow>0) 165 count++; 166 cout<<res<<" "<<count<<endl; 167 for(int i=1;i<=n;++i) 168 for(int j=head[i+n];j!=-1;j=edge[j].next) 169 if(edge[j].to!=2*n+1&&edge[j].flow>0) 170 cout<<i<<" "<<edge[j].to<<" "<<edge[j].flow<<endl; 171 return 0; 172 }
B. poj3281 Dining
建图方法:为使每一头牛都对应每一份食物与饮料,需要将每头牛拆点,一共有2*n+f+d+2个顶点,0表示源点,2*n+f+d+1表示汇点,由源点指向食物,再由食物指向牛,牛指向自己的对应点,再指向对应的饮料,饮料再指向汇点。全部是有向的边,而且权值全部为1,1到f为食物点,f+1到f+2*n为牛点,f+2*n+1到f+2*n+d为饮料点。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN = 500; 8 const int MAXM = 500*500; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 int gap[MAXN], dep[MAXN], cur[MAXN]; 17 void init() 18 { 19 tol = 0; 20 memset(head, -1, sizeof(head)); 21 } 22 void addedge(int u, int v, int w, int rw = 0) 23 { 24 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 25 edge[tol].next = head[u]; head[u] = tol++; 26 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 27 edge[tol].next = head[v]; head[v] = tol++; 28 } 29 int Q[MAXN]; 30 void BFS(int start, int end) 31 { 32 memset(dep, -1, sizeof(dep)); 33 memset(gap, 0, sizeof(gap)); 34 gap[0] = 1; 35 int front = 0, rear = 0; 36 dep[end] = 0; 37 Q[rear++] = end; 38 while(front != end) { 39 int u = Q[front++]; 40 for(int i = head[u]; i != -1; i = edge[i].next) { 41 int v = edge[i].to; 42 if(dep[v] != -1) continue; 43 Q[rear++] = v; 44 dep[v] = dep[u] + 1; 45 gap[dep[v]]++; 46 } 47 } 48 } 49 int S[MAXN]; 50 int sap(int start, int end, int N) { 51 BFS(start, end); 52 memcpy(cur, head, sizeof(head)); 53 int top = 0; 54 int u = start; 55 int ans = 0; 56 while(dep[start] < N) 57 { 58 if(u == end) 59 { 60 int Min = INF; 61 int inser; 62 for(int i = 0; i < top; i++) 63 if(Min > edge[S[i]].cap - edge[S[i]].flow) { 64 Min = edge[S[i]].cap - edge[S[i]].flow; 65 inser = i; 66 } 67 for(int i = 0; i < top; i++) 68 { 69 edge[S[i]].flow += Min; 70 edge[S[i]^1].flow -= Min; 71 } 72 ans += Min; 73 top = inser; 74 u = edge[S[top]^1].to; 75 continue; 76 } 77 bool flag = false; 78 int v; 79 for(int i = cur[u]; i != -1; i = edge[i].next) 80 { 81 v = edge[i].to; 82 if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]) { 83 flag = true; 84 cur[u] = i; 85 break; 86 } 87 } 88 if(flag) 89 { 90 S[top++] = cur[u]; 91 u = v; 92 continue; 93 } 94 int Min = N; 95 for(int i = head[u]; i != -1; i = edge[i].next) 96 if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) 97 { 98 Min = dep[edge[i].to]; 99 cur[u] = i; 100 } 101 gap[dep[u]]--; 102 if(!gap[dep[u]]) return ans; 103 dep[u] = Min + 1; 104 gap[dep[u]]++; 105 if(u != start) u = edge[S[--top]^1].to; 106 } 107 return ans; 108 } 109 110 int f,n,d; 111 int main() 112 { 113 scanf("%d%d%d",&n,&f,&d); 114 init(); 115 for(int i=1;i<=n;++i) 116 { 117 int a,b,num; 118 scanf("%d%d",&a,&b); 119 for(int j=1;j<=a;++j) 120 { 121 scanf("%d",&num); 122 addedge(num,i+f,1); 123 } 124 for(int j=1;j<=b;++j) 125 { 126 scanf("%d",&num); 127 addedge(i+f+n,f+2*n+num,1); 128 } 129 addedge(f+i,f+n+i,1); 130 } 131 for(int i=1;i<=f;++i) 132 addedge(0,i,1); 133 for(int i=1;i<=d;++i) 134 addedge(f+2*n+i,f+2*n+d+1,1); 135 int res=sap(0,f+2*n+d+1,f+2*n+d+2); 136 cout<<res<<endl; 137 return 0; 138 }
C. poj1087 A Plug for UNIX
题目大意:这题题目意思实在太难懂,不过题目意思搞清楚之后还是比较好做的。
题目中有三种物品:插座,电器和转换器。
首先有n种插座,n种插座用字符串表示,这n种插座可以理解为是插在电源上的插座。
然后有m个电器,现在电器要充电,电器用字符串表示,每个电器都有自己需要插的插座
(这个插座可以不是那n个插在电源上的插座,可以是其他的插座)。
最后有k种转换器:s1 s2代表这个转换器可以将s1插座转换成s2插座,这些s1与s2也可以不是那n个插在电源上的插座。
给出这些个信息问你还有多少个电器没有插座可以用。
建图方法:
建一个源点,指向所有电器,容量为1。所有电器指向他们可以插的那个插头上,容量为1。
如果一个插头可以转换另一个插头,那么将s1指向s2,容量为无限大,将所有插在电源上的插头指向汇点,容量为1。
最后求源点到汇点的最大流即可,不过建图会比较复杂,因为涉及到字符串的处理,所以用map容器存储结点编号比较好做点。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 #include<map> 7 #include<string> 8 9 using namespace std; 10 const int MAXN = 1010; 11 const int MAXM = 1000020; 12 const int INF = 0x3f3f3f3f; 13 struct Edge 14 { 15 int to, next, cap, flow; 16 }edge[MAXM]; 17 int tol; 18 int head[MAXN]; 19 void init() 20 { 21 tol = 2; 22 memset(head, -1, sizeof(head)); 23 } 24 void addedge(int u, int v, int w, int rw=0) 25 { 26 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 27 edge[tol].next = head[u]; head[u] = tol++; 28 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 29 edge[tol].next = head[v]; head[v] = tol++; 30 } 31 int Q[MAXN]; 32 int dep[MAXN], cur[MAXN], sta[MAXN]; 33 bool bfs(int s, int t, int n) 34 { 35 int front = 0, tail = 0; 36 memset(dep, -1, sizeof(dep[0])*(n+1)); 37 dep[s] = 0; 38 Q[tail++] = s; 39 while(front < tail) 40 { 41 int u = Q[front++]; 42 for(int i = head[u]; i != -1; i = edge[i].next) 43 { 44 int v = edge[i].to; 45 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 46 dep[v] = dep[u] + 1; 47 if(v == t) return true; 48 Q[tail++] = v; 49 } 50 } 51 } 52 return false; 53 } 54 int dinic(int s, int t, int n) { 55 int maxflow = 0; 56 while(bfs(s, t, n)) { 57 for(int i = 0; i < n; i++) cur[i] = head[i]; 58 int u = s, tail = 0; 59 while(cur[s] != -1) 60 { 61 if(u == t) 62 { 63 int tp = INF; 64 for(int i = tail-1; i >= 0; i--) 65 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 66 maxflow+=tp; 67 for(int i = tail-1; i >= 0; i--) { 68 edge[sta[i]].flow+=tp; 69 edge[sta[i]^1].flow-=tp; 70 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 71 tail = i; 72 } 73 u = edge[sta[tail]^1].to; 74 } 75 else 76 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 77 { 78 sta[tail++] = cur[u]; 79 u = edge[cur[u]].to; 80 } 81 else 82 { 83 while(u != s && cur[u] == -1) 84 u = edge[sta[--tail]^1].to; 85 cur[u] = edge[cur[u]].next; 86 } 87 } 88 } 89 return maxflow; 90 } 91 92 map<string,int> m1,m2; 93 int n,m,k; 94 95 int main() 96 { 97 m1.clear(); 98 m2.clear(); 99 init(); 100 scanf("%d",&n); 101 for(int i=1;i<=n;++i) 102 { 103 string s; 104 cin>>s; 105 m1[s]=i; 106 addedge(0,i,1); 107 } 108 scanf("%d",&m); 109 int cnt=n; 110 for(int i=1;i<=m;++i) 111 { 112 string s1,s2; 113 cin>>s1>>s2; 114 m2[s1]=i+300; 115 if(m1[s2]==0) 116 m1[s2]=++cnt; 117 addedge(m1[s2],m2[s1],1); 118 addedge(m2[s1],400,1); 119 } 120 scanf("%d",&k); 121 string a1[MAXN],a2[MAXN]; 122 for(int i=1;i<=k;++i) 123 cin>>a1[i]>>a2[i]; 124 for(int i=1;i<=k;++i) 125 { 126 if(m1[a1[i]]==0) 127 m1[a1[i]]=++cnt; 128 if(m1[a2[i]]==0) 129 m1[a2[i]]=++cnt; 130 addedge(m1[a2[i]],m1[a1[i]],INF); 131 } 132 int res=dinic(0,400,401); 133 // cout<<m<<" "<<res<<endl; 134 cout<<m-res<<endl; 135 return 0; 136 }
D. poj2195 Going Home
题意:有若干个人和若干个房子在一个给定网格中,每人走一个都要一定花费,每个房子只能容纳一人,现要求让所有人进入房子,且总花费最小。
分析:简单题,题目中关键字为:每房子容纳一人,行走有花费,典型的最小费用最大流问题。建图加入超级终点和源点,注意对所有房子和人之间建立边。最后求最小费用最大流即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 7 using namespace std; 8 const int MAXN = 10000; 9 const int MAXM = 100000; 10 const int INF = 0x3f3f3f3f; 11 struct Edge 12 { 13 int to, next, cap, flow, cost; 14 }edge[MAXM]; 15 int head[MAXN], tol; 16 int pre[MAXN], dis[MAXN]; 17 bool vis[MAXN]; 18 int N; 19 void init(int n) 20 { 21 N = n; 22 tol = 0; 23 memset(head, -1, sizeof(head)); 24 } 25 void addedge(int u, int v, int cap, int cost) 26 { 27 edge[tol].to = v; edge[tol].cap = cap; 28 edge[tol].cost = cost; edge[tol].flow = 0; 29 edge[tol].next = head[u]; head[u] = tol++; 30 edge[tol].to = u; edge[tol].cap = 0; 31 edge[tol].cost = -cost; edge[tol].flow = 0; 32 edge[tol].next = head[v]; head[v] = tol++; 33 } 34 bool spfa(int s, int t) 35 { 36 queue<int> q; 37 for(int i = 0; i < N; i++) 38 { 39 dis[i] = INF; 40 vis[i] = false; 41 pre[i] = -1; 42 } 43 dis[s] = 0; vis[s] = true; 44 q.push(s); 45 while(!q.empty()) 46 { 47 int u = q.front(); 48 q.pop(); 49 vis[u] = false; 50 for(int i = head[u]; i != -1; i = edge[i].next) 51 { 52 int v = edge[i].to; 53 if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) 54 { 55 dis[v] = dis[u] + edge[i].cost; 56 pre[v] = i; 57 if(!vis[v]) 58 { 59 vis[v] = true; 60 q.push(v); 61 } 62 } 63 } 64 } 65 if(pre[t] == -1) return false; 66 else return true; 67 } 68 69 int minCostMaxflow(int s, int t, int &cost) 70 { 71 int flow = 0; 72 cost = 0; 73 while(spfa(s, t)) 74 { 75 int Min = INF; 76 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 77 { 78 if(Min > edge[i].cap - edge[i].flow) 79 Min = edge[i].cap - edge[i].flow; 80 } 81 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 82 { 83 edge[i].flow += Min; 84 edge[i^1].flow -= Min; 85 cost += edge[i].cost * Min; 86 } 87 flow += Min; 88 } 89 return flow; 90 } 91 92 int n,m; 93 char map[MAXN][MAXN]; 94 struct House 95 { 96 int x,y; 97 }house[MAXN]; 98 99 struct Man 100 { 101 int x,y; 102 }man[MAXN]; 103 104 int dist(int i,int j) 105 { 106 return abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y); 107 } 108 109 int main() 110 { 111 while(~scanf("%d%d",&n,&m)&&(n||m)) 112 { 113 for(int i=0;i<n;++i) 114 scanf("%s",map[i]); 115 int mnum=0,hnum=0; 116 int count=0; 117 for(int i=0;i<n;++i) 118 for(int j=0;j<m;++j) 119 { 120 if(map[i][j]=='m') 121 { 122 count++; 123 mnum++; 124 man[mnum].x=i+1; 125 man[mnum].y=j+1; 126 } 127 if(map[i][j]=='H') 128 { 129 hnum++; 130 house[hnum].x=i+1; 131 house[hnum].y=j+1; 132 } 133 } 134 init(2*count+2); 135 // cout<<count<<endl; 136 for(int i=1;i<=count;++i) 137 for(int j=1;j<=count;++j) 138 addedge(i,j+count,1,dist(i,j)); 139 for(int i=1;i<=count;++i) 140 { 141 addedge(0,i,1,0); 142 addedge(i+count,2*count+1,1,0); 143 } 144 int cost; 145 minCostMaxflow(0,2*count+1,cost); 146 cout<<cost<<endl; 147 } 148 return 0; 149 }
E. poj2516 Minimum Cost
分析:由于每种物品之间是独立的,所以可以将k种物品分开求最小费用再相加,即对每一种物品建一幅图。可以在建图前先判断是否需求全部能满足。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 7 using namespace std; 8 const int MAXN = 200; 9 const int MAXM = 40000; 10 const int INF = 0x3f3f3f3f; 11 struct Edge 12 { 13 int to, next, cap, flow, cost; 14 }edge[MAXM]; 15 int head[MAXN], tol; 16 int pre[MAXN], dis[MAXN]; 17 bool vis[MAXN]; 18 int N; 19 void init(int n) 20 { 21 N = n; 22 tol = 0; 23 memset(head, -1, sizeof(head)); 24 } 25 void addedge(int u, int v, int cap, int cost) 26 { 27 edge[tol].to = v; edge[tol].cap = cap; 28 edge[tol].cost = cost; edge[tol].flow = 0; 29 edge[tol].next = head[u]; head[u] = tol++; 30 edge[tol].to = u; edge[tol].cap = 0; 31 edge[tol].cost = -cost; edge[tol].flow = 0; 32 edge[tol].next = head[v]; head[v] = tol++; 33 } 34 bool spfa(int s, int t) 35 { 36 queue<int> q; 37 for(int i = 0; i < N; i++) 38 { 39 dis[i] = INF; 40 vis[i] = false; 41 pre[i] = -1; 42 } 43 dis[s] = 0; vis[s] = true; 44 q.push(s); 45 while(!q.empty()) 46 { 47 int u = q.front(); 48 q.pop(); 49 vis[u] = false; 50 for(int i = head[u]; i != -1; i = edge[i].next) 51 { 52 int v = edge[i].to; 53 if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) 54 { 55 dis[v] = dis[u] + edge[i].cost; 56 pre[v] = i; 57 if(!vis[v]) 58 { 59 vis[v] = true; 60 q.push(v); 61 } 62 } 63 } 64 } 65 if(pre[t] == -1) return false; 66 else return true; 67 } 68 69 int minCostMaxflow(int s, int t, int &cost) 70 { 71 int flow = 0; 72 cost = 0; 73 while(spfa(s, t)) 74 { 75 int Min = INF; 76 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 77 { 78 if(Min > edge[i].cap - edge[i].flow) 79 Min = edge[i].cap - edge[i].flow; 80 } 81 for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 82 { 83 edge[i].flow += Min; 84 edge[i^1].flow -= Min; 85 cost += edge[i].cost * Min; 86 } 87 flow += Min; 88 } 89 return flow; 90 } 91 92 int n,m,k; 93 int need[60][60],supply[60][60],cost[60][60],sumneed[60],sumsupply[60]; 94 int main() 95 { 96 while(scanf("%d%d%d",&n,&m,&k)) 97 { 98 if(n==0 && m==0 && k==0) 99 break; 100 memset(sumneed,0,sizeof(sumneed)); 101 memset(sumsupply,0,sizeof(sumsupply)); 102 for(int i=1;i<=n;++i) 103 for(int j=1;j<=k;++j) 104 { 105 scanf("%d",&need[i][j]); 106 sumneed[j]+=need[i][j]; 107 } 108 for(int i=1;i<=m;++i) 109 for(int j=1;j<=k;++j) 110 { 111 scanf("%d",&supply[i][j]); 112 sumsupply[j]+=supply[i][j]; 113 } 114 bool flag=true; 115 for(int i=1;i<=k;++i) 116 { 117 if(sumsupply[i]<sumneed[i]) 118 { 119 flag=false; 120 break; 121 } 122 } 123 int res=0; 124 for(int l=1;l<=k;++l) 125 { 126 init(m+n+2); 127 for(int i=1;i<=n;++i) 128 for(int j=1;j<=m;++j) 129 scanf("%d",&cost[i][j]); 130 for(int i=1;i<=m;++i) 131 for(int j=1;j<=n;++j) 132 addedge(i,j+m,need[j][l],cost[j][i]); 133 for(int i=1;i<=m;++i) 134 addedge(0,i,supply[i][l],0); 135 for(int i=1;i<=n;++i) 136 addedge(i+m,m+n+1,need[i][l],0); 137 int ans; 138 minCostMaxflow(0,m+n+1,ans); 139 res+=ans; 140 } 141 if(!flag) 142 cout<<-1<<endl; 143 else 144 cout<<res<<endl; 145 } 146 return 0; 147 }
F. poj1459 Power Network
分析:题意比较烦,整理清楚就知道是裸的最大流,需要增加一个超级源点和超级汇点,把所给的发电站都和超级源点相连,把所给的消耗站都和超级汇点相连,最后跑一遍最大流即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 7 using namespace std; 8 const int MAXN = 1200; 9 const int MAXM = 120*1200; 10 const int INF = 0x3f3f3f3f; 11 struct Edge 12 { 13 int to, next, cap, flow; 14 }edge[MAXM]; 15 int tol; 16 int head[MAXN]; 17 void init() 18 { 19 tol = 2; 20 memset(head, -1, sizeof(head)); 21 } 22 void addedge(int u, int v, int w, int rw=0) 23 { 24 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 25 edge[tol].next = head[u]; head[u] = tol++; 26 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 27 edge[tol].next = head[v]; head[v] = tol++; 28 } 29 int Q[MAXN]; 30 int dep[MAXN], cur[MAXN], sta[MAXN]; 31 bool bfs(int s, int t, int n) 32 { 33 int front = 0, tail = 0; 34 memset(dep, -1, sizeof(dep[0])*(n+1)); 35 dep[s] = 0; 36 Q[tail++] = s; 37 while(front < tail) 38 { 39 int u = Q[front++]; 40 for(int i = head[u]; i != -1; i = edge[i].next) 41 { 42 int v = edge[i].to; 43 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 44 dep[v] = dep[u] + 1; 45 if(v == t) return true; 46 Q[tail++] = v; 47 } 48 } 49 } 50 return false; 51 } 52 int dinic(int s, int t, int n) { 53 int maxflow = 0; 54 while(bfs(s, t, n)) { 55 for(int i = 0; i < n; i++) cur[i] = head[i]; 56 int u = s, tail = 0; 57 while(cur[s] != -1) 58 { 59 if(u == t) 60 { 61 int tp = INF; 62 for(int i = tail-1; i >= 0; i--) 63 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 64 maxflow+=tp; 65 for(int i = tail-1; i >= 0; i--) { 66 edge[sta[i]].flow+=tp; 67 edge[sta[i]^1].flow-=tp; 68 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 69 tail = i; 70 } 71 u = edge[sta[tail]^1].to; 72 } 73 else 74 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 75 { 76 sta[tail++] = cur[u]; 77 u = edge[cur[u]].to; 78 } 79 else 80 { 81 while(u != s && cur[u] == -1) 82 u = edge[sta[--tail]^1].to; 83 cur[u] = edge[cur[u]].next; 84 } 85 } 86 } 87 return maxflow; 88 } 89 int n,np,nc,m; 90 char s[30]; 91 int u,v,z; 92 int main() 93 { 94 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)) 95 { 96 init(); 97 for(int i=1;i<=m;++i) 98 { 99 scanf("%s",s); 100 sscanf(s,"(%d,%d)%d",&u,&v,&z); 101 addedge(u+1,v+1,z); 102 } 103 for(int i=1;i<=np;++i) 104 { 105 scanf("%s",s); 106 sscanf(s,"(%d)%d",&u,&z); 107 addedge(0,u+1,z); 108 } 109 for(int i=1;i<=nc;++i) 110 { 111 scanf("%s",s); 112 sscanf(s,"(%d)%d",&u,&z); 113 addedge(u+1,n+2,z); 114 } 115 cout<<dinic(0,n+2,n+3)<<endl; 116 } 117 return 0; 118 }
G. hdu4280 Island Transport
分析:裸的最大流,但是由于边数比较多,容易超时和爆栈,我本来是存双向边的,T了好几发,修改了存边方式9000+ms水过。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN = 100010; 8 const int MAXM = 1200012; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int from,to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 void init() 17 { 18 tol = 2; 19 memset(head, -1, sizeof(head)); 20 } 21 int min(int a,int b) 22 { 23 return a>b?b:a; 24 } 25 void addedge(int u, int v, int w, int rw=0) 26 { 27 edge[tol].from=u; 28 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 29 edge[tol].next = head[u]; head[u] = tol++; 30 } 31 int Q[MAXN]; 32 int dep[MAXN], cur[MAXN], sta[MAXN]; 33 bool bfs(int s, int t, int n) 34 { 35 int front = 0, tail = 0; 36 memset(dep, -1, sizeof(dep[0])*(n+1)); 37 dep[s] = 0; 38 Q[tail++] = s; 39 while(front < tail) 40 { 41 int u = Q[front++]; 42 for(int i = head[u]; i != -1; i = edge[i].next) 43 { 44 int v = edge[i].to; 45 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 46 dep[v] = dep[u] + 1; 47 if(v == t) return true; 48 Q[tail++] = v; 49 } 50 } 51 } 52 return false; 53 } 54 int dinic(int s, int t, int n) { 55 int maxflow = 0; 56 while(bfs(s, t, n)) { 57 for(int i = 0; i < n; i++) cur[i] = head[i]; 58 int u = s, tail = 0; 59 while(cur[s] != -1) 60 { 61 if(u == t) 62 { 63 int tp = INF; 64 for(int i = tail-1; i >= 0; i--) 65 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 66 maxflow+=tp; 67 for(int i = tail-1; i >= 0; i--) { 68 edge[sta[i]].flow+=tp; 69 edge[sta[i]^1].flow-=tp; 70 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 71 tail = i; 72 } 73 u = edge[sta[tail]].from; 74 } 75 else 76 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 77 { 78 sta[tail++] = cur[u]; 79 u = edge[cur[u]].to; 80 } 81 else 82 { 83 while(u != s && cur[u] == -1) 84 u = edge[sta[--tail]].from; 85 cur[u] = edge[cur[u]].next; 86 } 87 } 88 } 89 return maxflow; 90 } 91 int n,m; 92 struct Node 93 { 94 int x,y; 95 }node[MAXN]; 96 97 int main() 98 { 99 int t; 100 scanf("%d",&t); 101 while(t--) 102 { 103 scanf("%d%d",&n,&m); 104 Node a,b; 105 init(); 106 int num1,num2; 107 a.x=INF; 108 b.x=-INF; 109 for(int i=1;i<=n;++i) 110 { 111 int x,y; 112 scanf("%d%d",&x,&y); 113 if(x<a.x) 114 { 115 a.x=x; 116 num1=i-1; 117 } 118 if(x>b.x) 119 { 120 b.x=x; 121 num2=i-1; 122 } 123 } 124 for(int i=1;i<=m;++i) 125 { 126 int u,v,c; 127 scanf("%d%d%d",&u,&v,&c); 128 addedge(u-1,v-1,c); 129 addedge(v-1,u-1,c); 130 } 131 cout<<dinic(num1,num2,n)<<endl; 132 } 133 return 0; 134 } 135
H. hdu4292 Food
分析:为了控制一个人只连一瓶饮料,一份食物,那么我们可以把一个人拆成两个,他们之间连一条权值为1的边,另外左边连它喜欢的食物,权值为1,右边连它喜欢的饮料,权值为1,在源点连食物的时候加流量限制,汇点加流量限制,跑一遍最大流即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int INF = 0x3f3f3f3f; 8 const int MAXN = 1000; 9 const int MAXM = 9000000; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 void init() 17 { 18 tol = 2; 19 memset(head, -1, sizeof(head)); 20 } 21 void addedge(int u, int v, int w, int rw=0) 22 { 23 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 24 edge[tol].next = head[u]; head[u] = tol++; 25 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 26 edge[tol].next = head[v]; head[v] = tol++; 27 } 28 int Q[MAXN]; 29 int dep[MAXN], cur[MAXN], sta[MAXN]; 30 bool bfs(int s, int t, int n) 31 { 32 int front = 0, tail = 0; 33 memset(dep, -1, sizeof(dep[0])*(n+1)); 34 dep[s] = 0; 35 Q[tail++] = s; 36 while(front < tail) 37 { 38 int u = Q[front++]; 39 for(int i = head[u]; i != -1; i = edge[i].next) 40 { 41 int v = edge[i].to; 42 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 43 dep[v] = dep[u] + 1; 44 if(v == t) return true; 45 Q[tail++] = v; 46 } 47 } 48 } 49 return false; 50 } 51 int dinic(int s, int t, int n) { 52 int maxflow = 0; 53 while(bfs(s, t, n)) { 54 for(int i = 0; i < n; i++) cur[i] = head[i]; 55 int u = s, tail = 0; 56 while(cur[s] != -1) 57 { 58 if(u == t) 59 { 60 int tp = INF; 61 for(int i = tail-1; i >= 0; i--) 62 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 63 maxflow+=tp; 64 for(int i = tail-1; i >= 0; i--) { 65 edge[sta[i]].flow+=tp; 66 edge[sta[i]^1].flow-=tp; 67 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 68 tail = i; 69 } 70 u = edge[sta[tail]^1].to; 71 } 72 else 73 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 74 { 75 sta[tail++] = cur[u]; 76 u = edge[cur[u]].to; 77 } 78 else 79 { 80 while(u != s && cur[u] == -1) 81 u = edge[sta[--tail]^1].to; 82 cur[u] = edge[cur[u]].next; 83 } 84 } 85 } 86 return maxflow; 87 } 88 int num,n,f,d; 89 char s[MAXN]; 90 91 int main() 92 { 93 while(~scanf("%d%d%d",&n,&f,&d)) 94 { 95 init(); 96 for(int i=1;i<=f;++i) 97 { 98 scanf("%d",&num); 99 addedge(0,i,num); 100 } 101 for(int i=1;i<=d;++i) 102 { 103 scanf("%d",&num); 104 addedge(f+2*n+i,f+2*n+d+1,num); 105 } 106 for(int i=1;i<=n;++i) 107 { 108 addedge(f+i,f+n+i,1); 109 scanf("%s",s); 110 for(int j=1;j<=f;++j) 111 if(s[j-1]=='Y') 112 addedge(j,i+f,1); 113 } 114 for(int i=1;i<=n;++i) 115 { 116 scanf("%s",s); 117 for(int j=1;j<=d;++j) 118 if(s[j-1]=='Y') 119 addedge(i+f+n,f+2*n+j,1); 120 } 121 cout<<dinic(0,f+2*n+d+1,f+2*n+d+2)<<endl; 122 } 123 return 0; 124 }
I. hdu4289 Control
题意:给出一个由n个点,m条边组成的无向图。给出两个点s,t。对于图中的每个点,去掉这个点都需要一定的花费。求至少多少花费才能使得s和t之间不连通。
分析:题意即求最小割,将每个点拆点,点与对应点的边权为去掉该点的花费,原图中所有边的边权赋为无穷大,跑一遍最大流即可。(最大流即最小割)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN = 2010; 8 const int MAXM = 1200012; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 void init() 17 { 18 tol = 2; 19 memset(head, -1, sizeof(head)); 20 } 21 void addedge(int u, int v, int w, int rw=0) 22 { 23 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 24 edge[tol].next = head[u]; head[u] = tol++; 25 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 26 edge[tol].next = head[v]; head[v] = tol++; 27 } 28 int Q[MAXN]; 29 int dep[MAXN], cur[MAXN], sta[MAXN]; 30 bool bfs(int s, int t, int n) 31 { 32 int front = 0, tail = 0; 33 memset(dep, -1, sizeof(dep[0])*(n+1)); 34 dep[s] = 0; 35 Q[tail++] = s; 36 while(front < tail) 37 { 38 int u = Q[front++]; 39 for(int i = head[u]; i != -1; i = edge[i].next) 40 { 41 int v = edge[i].to; 42 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 43 dep[v] = dep[u] + 1; 44 if(v == t) return true; 45 Q[tail++] = v; 46 } 47 } 48 } 49 return false; 50 } 51 int dinic(int s, int t, int n) { 52 int maxflow = 0; 53 while(bfs(s, t, n)) { 54 for(int i = 0; i < n; i++) cur[i] = head[i]; 55 int u = s, tail = 0; 56 while(cur[s] != -1) 57 { 58 if(u == t) 59 { 60 int tp = INF; 61 for(int i = tail-1; i >= 0; i--) 62 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 63 maxflow+=tp; 64 for(int i = tail-1; i >= 0; i--) { 65 edge[sta[i]].flow+=tp; 66 edge[sta[i]^1].flow-=tp; 67 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 68 tail = i; 69 } 70 u = edge[sta[tail]^1].to; 71 } 72 else 73 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 74 { 75 sta[tail++] = cur[u]; 76 u = edge[cur[u]].to; 77 } 78 else 79 { 80 while(u != s && cur[u] == -1) 81 u = edge[sta[--tail]^1].to; 82 cur[u] = edge[cur[u]].next; 83 } 84 } 85 } 86 return maxflow; 87 } 88 int n,m,s,d; 89 90 int main() 91 { 92 while(~scanf("%d%d",&n,&m)) 93 { 94 init(); 95 scanf("%d%d",&s,&d); 96 int c; 97 for(int i=0;i<n;++i) 98 { 99 scanf("%d",&c); 100 addedge(i,i+n,c); 101 } 102 for(int i=1;i<=m;++i) 103 { 104 int a,b; 105 scanf("%d%d",&a,&b); 106 addedge(a-1+n,b-1,INF); 107 addedge(b-1+n,a-1,INF); 108 } 109 cout<<dinic(s-1,d-1+n,2*n)<<endl; 110 } 111 return 0; 112 }
J. UVA10480 Sabotage
题意:旧政府有一个很庞大的网络系统,可以很方便的指挥他的城市,起义军为了减少伤亡所以决定破坏他们的网络,使他们的首都(1号城市)和最大的城市(2号城市)不能联
系,不过破坏不同的网络所花费的代价是不同的,现在起义军想知道最少花费的代价是多少,输出需要破坏的线路。
分析:与 I 题一样,也是求最小割,只要算出最大流即可。不过题目要求输出最小割的边,这也是可以用网络流解决的,方法:求完最大流后,在残留网络中从源点 s 开始 dfs ,将能
到达的点标号( c - f >0 的边),最后遍历一遍边集,将起点被标记、终点未被标记的边输出。(注意这是无向图,边只用输出一遍,而在有向图中,条件应该改为起点标号、终点未标或起点未标、终点标号的边)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 7 using namespace std; 8 const int MAXN = 200; 9 const int MAXM = 5000; 10 const int INF = 0x3f3f3f3f; 11 struct Edge 12 { 13 int from,to, next, cap, flow; 14 }edge[MAXM]; 15 int tol; 16 int head[MAXN]; 17 void init() 18 { 19 tol = 2; 20 memset(head, -1, sizeof(head)); 21 } 22 int min(int a,int b) 23 { 24 return a>b?b:a; 25 } 26 void addedge(int u, int v, int w, int rw=0) 27 { 28 edge[tol].from=u; 29 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 30 edge[tol].next = head[u]; head[u] = tol++; 31 } 32 int Q[MAXN]; 33 int dep[MAXN], cur[MAXN], sta[MAXN]; 34 bool bfs(int s, int t, int n) 35 { 36 int front = 0, tail = 0; 37 memset(dep, -1, sizeof(dep[0])*(n+1)); 38 dep[s] = 0; 39 Q[tail++] = s; 40 while(front < tail) 41 { 42 int u = Q[front++]; 43 for(int i = head[u]; i != -1; i = edge[i].next) 44 { 45 int v = edge[i].to; 46 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 47 dep[v] = dep[u] + 1; 48 if(v == t) return true; 49 Q[tail++] = v; 50 } 51 } 52 } 53 return false; 54 } 55 int dinic(int s, int t, int n) { 56 int maxflow = 0; 57 while(bfs(s, t, n)) { 58 for(int i = 0; i < n; i++) cur[i] = head[i]; 59 int u = s, tail = 0; 60 while(cur[s] != -1) 61 { 62 if(u == t) 63 { 64 int tp = INF; 65 for(int i = tail-1; i >= 0; i--) 66 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 67 maxflow+=tp; 68 for(int i = tail-1; i >= 0; i--) { 69 edge[sta[i]].flow+=tp; 70 edge[sta[i]^1].flow-=tp; 71 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 72 tail = i; 73 } 74 u = edge[sta[tail]].from; 75 } 76 else 77 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 78 { 79 sta[tail++] = cur[u]; 80 u = edge[cur[u]].to; 81 } 82 else 83 { 84 while(u != s && cur[u] == -1) 85 u = edge[sta[--tail]].from; 86 cur[u] = edge[cur[u]].next; 87 } 88 } 89 } 90 return maxflow; 91 } 92 int n,m; 93 bool vis[MAXN]; 94 95 void dfs(int u) 96 { 97 vis[u]=true; 98 for(int i=head[u];i!=-1;i=edge[i].next) 99 { 100 int v=edge[i].to; 101 if(edge[i].cap>edge[i].flow&&(!vis[v])) 102 dfs(v); 103 } 104 } 105 106 int main() 107 { 108 while(~scanf("%d%d",&n,&m)&&n&&m) 109 { 110 init(); 111 for(int i=1;i<=m;++i) 112 { 113 int u,v,c; 114 scanf("%d%d%d",&u,&v,&c); 115 addedge(u-1,v-1,c); 116 addedge(v-1,u-1,c); 117 } 118 dinic(0,1,n); 119 memset(vis,false,sizeof(vis)); 120 dfs(0); 121 for(int i=2;i<tol;i=i+2) 122 { 123 int u=edge[i].from; 124 int v=edge[i].to; 125 if(vis[u]!=vis[v]) 126 { 127 cout<<u+1<<" "<<v+1<<endl; 128 } 129 } 130 cout<<endl; 131 } 132 return 0; 133 }
K. hdu2732 Leapin' Lizards
题意:给你一个网格,网格上的一些位置上有一只蜥蜴,所有蜥蜴的最大跳跃距离是d,如果一只蜥蜴能跳出网格边缘,那么它就安全了。且每个网格有一个最大跳出次数x,即最多有x只蜥蜴从这个网格跳出,这个网格就再也不能有蜥蜴进来了。问你最少有多少只蜥蜴跳不出网格。
分析:这是一道最大流。源点S编号0,网格的每个格子分成两个点i和i+n*m(n和m为网格的行和列数,i编号点是表示蜥蜴进来,而i+n*m编号的点是表示蜥蜴出去)。汇点t编号n*m*2+1。如果格子i上有蜥蜴,那么从s到i有边(s,i,1)。如果格子i能承受x次跳出,那么有边(i,i+n*m,x)。如果从格子i能直接跳出网格边界,那么有边(i+n*m,t,INF)。如果从格子i不能直接跳出网格,那么从i到离i距离<=d的网格j有边(i+n*m,j,INF),注意这里的距离是曼哈顿距离。最终我们求出的最大流就是能跳出网格的蜥蜴数。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN = 2010; 8 const int MAXM = 1200012; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 void init() 17 { 18 tol = 2; 19 memset(head, -1, sizeof(head)); 20 } 21 void addedge(int u, int v, int w, int rw=0) 22 { 23 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 24 edge[tol].next = head[u]; head[u] = tol++; 25 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 26 edge[tol].next = head[v]; head[v] = tol++; 27 } 28 int Q[MAXN]; 29 int dep[MAXN], cur[MAXN], sta[MAXN]; 30 bool bfs(int s, int t, int n) 31 { 32 int front = 0, tail = 0; 33 memset(dep, -1, sizeof(dep[0])*(n+1)); 34 dep[s] = 0; 35 Q[tail++] = s; 36 while(front < tail) 37 { 38 int u = Q[front++]; 39 for(int i = head[u]; i != -1; i = edge[i].next) 40 { 41 int v = edge[i].to; 42 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 43 dep[v] = dep[u] + 1; 44 if(v == t) return true; 45 Q[tail++] = v; 46 } 47 } 48 } 49 return false; 50 } 51 int dinic(int s, int t, int n) { 52 int maxflow = 0; 53 while(bfs(s, t, n)) { 54 for(int i = 0; i < n; i++) cur[i] = head[i]; 55 int u = s, tail = 0; 56 while(cur[s] != -1) 57 { 58 if(u == t) 59 { 60 int tp = INF; 61 for(int i = tail-1; i >= 0; i--) 62 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 63 maxflow+=tp; 64 for(int i = tail-1; i >= 0; i--) { 65 edge[sta[i]].flow+=tp; 66 edge[sta[i]^1].flow-=tp; 67 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 68 tail = i; 69 } 70 u = edge[sta[tail]^1].to; 71 } 72 else 73 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 74 { 75 sta[tail++] = cur[u]; 76 u = edge[cur[u]].to; 77 } 78 else 79 { 80 while(u != s && cur[u] == -1) 81 u = edge[sta[--tail]^1].to; 82 cur[u] = edge[cur[u]].next; 83 } 84 } 85 } 86 return maxflow; 87 } 88 int t,n,d; 89 char s[30]; 90 int map[30][30]; 91 92 int main() 93 { 94 int t; 95 scanf("%d",&t); 96 for(int k=1;k<=t;++k) 97 { 98 init(); 99 scanf("%d%d",&n,&d); 100 memset(map,0,sizeof(map)); 101 scanf("%s",s); 102 int m=strlen(s); 103 for(int i=0;i<m;++i) 104 map[1][i+1]=s[i]-'0'; 105 for(int i=2;i<=n;++i) 106 { 107 scanf("%s",s); 108 for(int j=1;j<=m;++j) 109 map[i][j]=s[j-1]-'0'; 110 } 111 int sum=0; 112 for(int i=1;i<=n;++i) 113 { 114 scanf("%s",s); 115 for(int j=1;j<=m;++j) 116 if(s[j-1]=='L') 117 { 118 sum++; 119 addedge(0,(i-1)*m+j,1); 120 } 121 } 122 for(int i=1;i<=n;++i) 123 for(int j=1;j<=m;++j) 124 { 125 int num=(i-1)*m+j; 126 if(map[i][j]==0) 127 continue; 128 addedge(num,num+n*m,map[i][j]); 129 if(i<=d||n-i<d||j<=d||m-j<d) 130 addedge(num+n*m,2*n*m+1,INF); 131 else 132 { 133 for(int a=1;a<=n;++a) 134 for(int b=1;b<=m;++b) 135 { 136 int id=(a-1)*m+b; 137 if(id==num) 138 continue; 139 if(abs(i-a)+abs(j-b)<=d&&map[a][b]>0) 140 addedge(num+n*m,id,INF); 141 } 142 } 143 } 144 int ans=sum-dinic(0,2*n*m+1,2*n*m+2); 145 printf("Case #%d: ",k); 146 if(ans==0) 147 printf("no lizard was left behind. "); 148 else 149 { 150 if(ans==1) 151 printf("1 lizard was left behind. "); 152 else 153 printf("%d lizards were left behind. ",ans); 154 } 155 } 156 return 0; 157 }
L. hdu3338 Kakuro Extension
分析:这道题可以用网络流来做。以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变。求满足的最大流。由于流量有上下限限制,可以给每个数都减掉1,则填出来的数字范围为0—8, 就可以用单纯的网络流搞定了。求出来再加上就可以了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN = 20100; 8 const int MAXM = 1200012; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 void init() 17 { 18 tol = 2; 19 memset(head, -1, sizeof(head)); 20 } 21 void addedge(int u, int v, int w, int rw=0) 22 { 23 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 24 edge[tol].next = head[u]; head[u] = tol++; 25 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 26 edge[tol].next = head[v]; head[v] = tol++; 27 } 28 int Q[MAXN]; 29 int dep[MAXN], cur[MAXN], sta[MAXN]; 30 bool bfs(int s, int t, int n) 31 { 32 int front = 0, tail = 0; 33 memset(dep, -1, sizeof(dep[0])*(n+1)); 34 dep[s] = 0; 35 Q[tail++] = s; 36 while(front < tail) 37 { 38 int u = Q[front++]; 39 for(int i = head[u]; i != -1; i = edge[i].next) 40 { 41 int v = edge[i].to; 42 if(edge[i].cap > edge[i].flow && dep[v] == -1) { 43 dep[v] = dep[u] + 1; 44 if(v == t) return true; 45 Q[tail++] = v; 46 } 47 } 48 } 49 return false; 50 } 51 int dinic(int s, int t, int n) { 52 int maxflow = 0; 53 while(bfs(s, t, n)) { 54 for(int i = 0; i < n; i++) cur[i] = head[i]; 55 int u = s, tail = 0; 56 while(cur[s] != -1) 57 { 58 if(u == t) 59 { 60 int tp = INF; 61 for(int i = tail-1; i >= 0; i--) 62 tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow); 63 maxflow+=tp; 64 for(int i = tail-1; i >= 0; i--) { 65 edge[sta[i]].flow+=tp; 66 edge[sta[i]^1].flow-=tp; 67 if(edge[sta[i]].cap-edge[sta[i]].flow==0) 68 tail = i; 69 } 70 u = edge[sta[tail]^1].to; 71 } 72 else 73 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 74 { 75 sta[tail++] = cur[u]; 76 u = edge[cur[u]].to; 77 } 78 else 79 { 80 while(u != s && cur[u] == -1) 81 u = edge[sta[--tail]^1].to; 82 cur[u] = edge[cur[u]].next; 83 } 84 } 85 } 86 return maxflow; 87 } 88 struct node 89 { 90 int x,y; 91 int tmp; 92 }s[11000],t[11000]; 93 int n,m; 94 int a,b; 95 int num[120][120][3],f[120][120]; 96 char str[100]; 97 98 int main() 99 { 100 while(~scanf("%d%d",&n,&m)) 101 { 102 memset(num,0,sizeof(num)); 103 a=b=0; 104 init(); 105 for(int i=1;i<=n;++i) 106 { 107 for(int j=1;j<=m;++j) 108 { 109 scanf("%s",str); 110 // int len=strlen(str); 111 if(str[0]=='.') 112 { 113 num[i][j][0]=-1; 114 continue; 115 } 116 if(str[0]!='X') 117 { 118 num[i][j][1]=(str[0]-'0')*100+(str[1]-'0')*10+str[2]-'0'; 119 s[a].x=i; 120 s[a].y=j; 121 s[a++].tmp=num[i][j][1]; 122 } 123 if(str[4]!='X') 124 { 125 num[i][j][2]=(str[4]-'0')*100+(str[5]-'0')*10+str[6]-'0'; 126 t[b].x=i; 127 t[b].y=j; 128 t[b++].tmp=num[i][j][2]; 129 } 130 } 131 } 132 /* for(int i=1;i<=n;++i) 133 { 134 for(int j=1;j<=m;++j) 135 { 136 cout<<num[i][j][0]<<" "<<num[i][j][1]<<" "<<num[i][j][2]<<" "; 137 } 138 cout<<endl; 139 }*/ 140 for(int i=0;i<a;++i) 141 { 142 int id=(s[i].x-1)*m+s[i].y; 143 // addedge(0,id,s[i].tmp); 144 int snum=0; 145 for(int j=s[i].x+1;j<=n;++j) 146 { 147 if(num[j][s[i].y][0]==0) 148 break; 149 int count=(j-1)*m+s[i].y; 150 snum++; 151 addedge(id,count,8); 152 } 153 addedge(0,id,s[i].tmp-snum); 154 // cout<<id<<" "<<s[i].tmp-snum<<endl; 155 } 156 for(int i=0;i<b;++i) 157 { 158 int id=(t[i].x-1)*m+t[i].y+n*m; 159 // addedge(id,2*n*m+1,t[i].tmp); 160 int tnum=0; 161 for(int j=t[i].y+1;j<=m;++j) 162 { 163 if(num[t[i].x][j][0]==0) 164 break; 165 int count=(t[i].x-1)*m+j; 166 tnum++; 167 addedge(count,id,8); 168 } 169 addedge(id,2*n*m+1,t[i].tmp-tnum); 170 // cout<<id<<" "<<t[i].tmp-tnum<<endl; 171 } 172 int res=dinic(0,2*n*m+1,2*n*m+2); 173 // cout<<res<<endl; 174 memset(f,0,sizeof(f)); 175 for(int i=2;i<tol;++i) 176 { 177 int c=edge[i].to; 178 int y=c%m; 179 if(y==0) 180 y=m; 181 int x=(c-y)/m+1; 182 // cout<<x<<" "<<y<<" "<<edge[i].flow<<endl; 183 if(num[x][y][0]==-1&&edge[i].flow>0) 184 { 185 // cout<<x<<" "<<y<<" "<<edge[i].flow<<endl; 186 f[x][y]+=edge[i].flow; 187 } 188 } 189 for(int i=1;i<=n;++i) 190 { 191 for(int j=1;j<=m;++j) 192 { 193 if(j!=1) 194 cout<<" "; 195 if(num[i][j][0]==-1) 196 cout<<f[i][j]+1; 197 else 198 cout<<"_"; 199 } 200 cout<<endl; 201 } 202 } 203 return 0; 204 }
M. hdu3605 Escape
题意:这题题意很简单,现有n个人要移居到m个星球去,给定一个n*m的矩阵,第 i 行第 j 列如果为1,表示第 i 个人可以去第 j 个星球,如果为0,表示不可以去。
分析:显然是个最大流问题,这题解题的关键在于建图,如果把每个人看做一个点,每个星球看做一个点,人到所有可以去的星球都连上边,那么整个图的边数在10^6,那么就会TLE,那么该怎么建图呢?注意到最多只有10个星球,如果两个人能够居住的星球的情况相同,则可以认为这两个人是同一类人,这样最多只有1024种人,点的数目大大减少,最后将每类人与适合这类人居住的星球建边跑最大流即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 6 using namespace std; 7 const int MAXN = 201000; 8 const int MAXM = 1200012; 9 const int INF = 0x3f3f3f3f; 10 struct Edge 11 { 12 int to, next, cap, flow; 13 }edge[MAXM]; 14 int tol; 15 int head[MAXN]; 16 int gap[MAXN], dep[MAXN], cur[MAXN]; 17 int count[1200]; 18 void init() 19 { 20 tol = 0; 21 memset(head, -1, sizeof(head)); 22 memset(count,0,sizeof(count)); 23 } 24 void addedge(int u, int v, int w, int rw = 0) 25 { 26 edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; 27 edge[tol].next = head[u]; head[u] = tol++; 28 edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; 29 edge[tol].next = head[v]; head[v] = tol++; 30 } 31 int Q[MAXN]; 32 void BFS(int start, int end) 33 { 34 memset(dep, -1, sizeof(dep)); 35 memset(gap, 0, sizeof(gap)); 36 gap[0] = 1; 37 int front = 0, rear = 0; 38 dep[end] = 0; 39 Q[rear++] = end; 40 while(front != end) { 41 int u = Q[front++]; 42 for(int i = head[u]; i != -1; i = edge[i].next) { 43 int v = edge[i].to; 44 if(dep[v] != -1) continue; 45 Q[rear++] = v; 46 dep[v] = dep[u] + 1; 47 gap[dep[v]]++; 48 } 49 } 50 } 51 int S[MAXN]; 52 int sap(int start, int end, int N) { 53 BFS(start, end); 54 memcpy(cur, head, sizeof(head)); 55 int top = 0; 56 int u = start; 57 int ans = 0; 58 while(dep[start] < N) 59 { 60 if(u == end) 61 { 62 int Min = INF; 63 int inser; 64 for(int i = 0; i < top; i++) 65 if(Min > edge[S[i]].cap - edge[S[i]].flow) { 66 Min = edge[S[i]].cap - edge[S[i]].flow; 67 inser = i; 68 } 69 for(int i = 0; i < top; i++) 70 { 71 edge[S[i]].flow += Min; 72 edge[S[i]^1].flow -= Min; 73 } 74 ans += Min; 75 top = inser; 76 u = edge[S[top]^1].to; 77 continue; 78 } 79 bool flag = false; 80 int v; 81 for(int i = cur[u]; i != -1; i = edge[i].next) 82 { 83 v = edge[i].to; 84 if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]) { 85 flag = true; 86 cur[u] = i; 87 break; 88 } 89 } 90 if(flag) 91 { 92 S[top++] = cur[u]; 93 u = v; 94 continue; 95 } 96 int Min = N; 97 for(int i = head[u]; i != -1; i = edge[i].next) 98 if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) 99 { 100 Min = dep[edge[i].to]; 101 cur[u] = i; 102 } 103 gap[dep[u]]--; 104 if(!gap[dep[u]]) return ans; 105 dep[u] = Min + 1; 106 gap[dep[u]]++; 107 if(u != start) u = edge[S[--top]^1].to; 108 } 109 return ans; 110 } 111 int n,m; 112 int main() 113 { 114 while(~scanf("%d%d",&n,&m)) 115 { 116 init(); 117 for(int i=1;i<=n;++i) 118 { 119 int num=0; 120 int c=1; 121 for(int j=1;j<=m;++j) 122 { 123 int a; 124 scanf("%d",&a); 125 num+=c*a; 126 c=c*2; 127 } 128 count[num]++; 129 } 130 for(int i=0;i<1024;++i) 131 { 132 addedge(0,i+1,count[i]); 133 int num=i; 134 int j=1; 135 while(num>0) 136 { 137 int a=num%2; 138 if(a==1) 139 addedge(i+1,1024+j,count[i]); 140 num=num/2; 141 j++; 142 } 143 } 144 for(int i=1;i<=m;++i) 145 { 146 int num; 147 scanf("%d",&num); 148 addedge(1024+i,1024+m+i,num); 149 addedge(1024+m+i,1024+2*m+1,INF); 150 } 151 int ans=sap(0,1024+2*m+1,1024+2*m+2); 152 if(ans==n) 153 cout<<"YES"<<endl; 154 else 155 cout<<"NO"<<endl; 156 } 157 return 0; 158 }
N. hdu3081 Marriage Match II
题解链接:http://www.cnblogs.com/yaoyueduzhen/p/5087404.html
O. hdu3416 Marriage Match IV