最小费用最大流入门
poj 3281
学会建图啊。。 啊。。 啊。。
S(0)-食物(2n+i)-牛1(i)-牛2(n+i)-饮料(2n+F+i)-T(2n+F+D+1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<set> 7 #include<map> 8 #include<stack> 9 #include<vector> 10 #include<queue> 11 #include<string> 12 #include<sstream> 13 #define eps 1e-9 14 #define ALL(x) x.begin(),x.end() 15 #define INS(x) inserter(x,x.begin()) 16 #define FOR(i,j,k) for(int i=j;i<=k;i++) 17 #define MAXN 1005 18 #define MAXM 30005 19 using namespace std; 20 typedef long long LL; 21 int i, j, k, n, m, x, y, T, ans, big, cas, F, D, S, f, d, id; 22 bool flag; 23 24 const int inf = 0x3f3f3f3f; 25 struct edgenode 26 { 27 int from, to, next; 28 int cap; 29 }edge[MAXM]; 30 int Edge, head[MAXN], ps[MAXN], dep[MAXN]; 31 32 void add_edge(int x, int y, int c) 33 { 34 edge[Edge].from = x; 35 edge[Edge].to = y; 36 edge[Edge].cap = c; 37 edge[Edge].next = head[x]; 38 head[x] = Edge++; 39 40 edge[Edge].from = y; 41 edge[Edge].to = x; 42 edge[Edge].cap = 0; 43 edge[Edge].next = head[y]; 44 head[y] = Edge++; 45 } 46 47 int dinic(int n, int s, int t) 48 { 49 int tr, flow = 0; 50 int i, j, k, l, r, top; 51 while (1){ 52 memset(dep, -1, (n + 1)*sizeof(int)); 53 for (l = dep[ps[0] = s] = 0, r = 1; l != r;)//BFS部分,将给定图分层 54 { 55 for (i = ps[l++], j = head[i]; j != -1; j = edge[j].next) 56 { 57 if (edge[j].cap&&-1 == dep[k = edge[j].to]) 58 { 59 dep[k] = dep[i] + 1; ps[r++] = k; 60 if (k == t) 61 { 62 l = r; 63 break; 64 } 65 } 66 } 67 } 68 if (dep[t] == -1)break; 69 70 for (i = s, top = 0;;)//DFS部分 71 { 72 if (i == t)//当前点就是汇点时 73 { 74 for (k = 0, tr = inf; k<top; ++k) 75 if (edge[ps[k]].cap<tr)tr = edge[ps[l = k]].cap; 76 77 for (k = 0; k<top; ++k) 78 edge[ps[k]].cap -= tr, edge[ps[k] ^ 1].cap += tr; 79 80 flow += tr; 81 i = edge[ps[top = l]].from; 82 } 83 84 for (j = head[i]; j != -1; j = edge[j].next)//找当前点所指向的点 85 if (edge[j].cap&&dep[i] + 1 == dep[edge[j].to]) break; 86 87 if (j != -1) 88 { 89 ps[top++] = j;//当前点有所指向的点,把这个点加入栈中 90 i = edge[j].to; 91 } 92 else 93 { 94 if (!top) break;//当前点没有指向的点,回溯 95 dep[i] = -1; 96 i = edge[ps[--top]].from; 97 } 98 } 99 } 100 return flow; 101 } 102 103 104 int main() 105 { 106 memset(head, -1, sizeof(head)); Edge = 0; 107 scanf("%d%d%d", &n, &F, &D); 108 S = 0; 109 T = n + n + F + D + 1; 110 for (i = 1; i <= F; i++) 111 { 112 add_edge(S, 2 * n + i, 1); 113 } 114 for (i = 1; i <= D; i++) 115 { 116 add_edge(2 * n + F + i, T, 1); 117 } 118 119 for (i = 1; i <= n; i++) 120 { 121 scanf("%d%d", &f, &d); 122 add_edge(i, n + i, 1); 123 for (j = 1; j <= f; j++) 124 { 125 scanf("%d", &id); 126 id = 2 * n + id; 127 add_edge(id, i, 1); 128 } 129 for (j = 1; j <= d; j++) 130 { 131 scanf("%d", &id); 132 id = 2 * n + F + id; 133 add_edge(n + i, id, 1); 134 } 135 } 136 printf("%d\n", dinic(T + 1, S, T)); 137 return 0; 138 }
poj 3469
将每个任务规约为一个点,添加源汇点s.t,s和每个任务相连,边权为任务在s上处理用的时间; 每个任务和t相连,边权为任务在t上处理用的时间.对于(a,b,w),连两条边(a,b,w)和(b,a,w); 为什么最小割就是解呢? 由最小割的定义,点基被分成两部分S.T,S为源点能到达的点的集合,其余点构成T; 再来看此题,假如s和a之间的边是割,那么a在s上被处理,否则a在t上被处理,s能到达的点在t上处理,其余点在t上处理;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 #define M 6050000 6 #define N 20200 7 #define inf 0x3f3f3f3f 8 using namespace std; 9 10 11 struct node { 12 int v,w,next; 13 } edge[M]; 14 int head[N],cnt,l[N],n,m,s,t; 15 void add(int u,int v,int w) { 16 edge[cnt].v=v; 17 edge[cnt].w=w; 18 edge[cnt].next=head[u]; 19 head[u]=cnt++; 20 21 edge[cnt].v=u; 22 edge[cnt].w=0; 23 edge[cnt].next=head[v]; 24 head[v]=cnt++; 25 } 26 void add2(int u,int v,int w) { 27 edge[cnt].v=v; 28 edge[cnt].w=w; 29 edge[cnt].next=head[u]; 30 head[u]=cnt++; 31 32 edge[cnt].v=u; 33 edge[cnt].w=w; 34 edge[cnt].next=head[v]; 35 head[v]=cnt++; 36 } 37 int bfs() { 38 memset(l,-1,sizeof(l)); 39 l[s]=0; 40 int i,u,v; 41 queue<int >Q; 42 Q.push(s); 43 while(!Q.empty()) { 44 u=Q.front(); 45 Q.pop(); 46 for(i=head[u]; i!=-1; i=edge[i].next) { 47 v=edge[i].v; 48 if(l[v]==-1&&edge[i].w) { 49 l[v]=l[u]+1; 50 Q.push(v); 51 } 52 } 53 } 54 return l[t]>0; 55 } 56 int dfs(int u,int f) { 57 int a,flow=0; 58 if(u==t)return f; 59 for(int i=head[u]; i!=-1; i=edge[i].next) { 60 int v=edge[i].v; 61 if(l[v]==l[u]+1&&edge[i].w&&(a=dfs(v,min(f,edge[i].w)))) { 62 edge[i].w-=a; 63 edge[i^1].w+=a; 64 flow+=a;//多路增广 65 f-=a; 66 if(!f)break; 67 } 68 } 69 if(!flow)l[u]=-1;//当前弧优化 70 return flow; 71 } 72 int dinic() { 73 int a,ans=0; 74 while(bfs()) 75 while(a=dfs(s,inf)) 76 ans+=a; 77 return ans; 78 } 79 80 int main() { 81 int i,j,u,v,w; 82 while(~scanf("%d%d",&n,&m)) { 83 memset(head,-1,sizeof(head)); 84 cnt=0; 85 s=0; 86 t=n+1; 87 for(i=1; i<=n; i++) { 88 scanf("%d%d",&u,&v); 89 add(s,i,u); 90 add(i,t,v); 91 } 92 for(i=1; i<=m; i++) { 93 scanf("%d%d%d",&u,&v,&w); 94 add2(u,v,w); 95 } 96 printf("%d\n",dinic()); 97 } 98 }
poj 2175
消圈判断费用流是否最优
请看http://m.blog.csdn.net/blog/u013761036/46363631
大牛代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<queue> 2 #include<stdio.h> 3 #include<string.h> 4 5 #define N_node 205 6 #define N_edge 30000 7 #define INF 100000000 8 9 using namespace std; 10 11 typedef struct 12 { 13 int from ,to ,cost ,flow ,next; 14 }STAR; 15 16 typedef struct 17 { 18 int a ,b ,c; 19 }NODE; 20 21 STAR E[N_edge]; 22 int list[N_node] ,tot; 23 int C[N_node];//入队次数 24 int mer[N_node];//记录路径 25 int s_x[N_node] ,mark[N_node]; 26 int now[N_node][N_node]; 27 NODE A[N_node] ,B[N_node]; 28 29 void add(int a ,int b ,int c ,int d) 30 { 31 E[++tot].from = a; 32 E[tot].to = b; 33 E[tot].cost = c; 34 E[tot].flow = d; 35 E[tot].next = list[a]; 36 list[a] = tot; 37 } 38 39 int abss(int x) 40 { 41 return x > 0 ? x : -x; 42 } 43 44 bool Spfa(int s ,int n) 45 { 46 for(int i = 0 ;i <= n ;i ++) 47 s_x[i] = INF; 48 memset(mark ,0 ,sizeof(mark)); 49 memset(C ,0 ,sizeof(C)); 50 queue<int>q; q.push(s); 51 mark[s] = C[s] = 1 ,s_x[s] = 0; 52 int xin ,tou; 53 memset(mer ,255 ,sizeof(mer)); 54 while(!q.empty()) 55 { 56 tou = q.front(); 57 q.pop(); 58 mark[tou] = 0; 59 for(int k = list[tou] ;k ;k = E[k].next) 60 { 61 xin = E[k].to; 62 if(s_x[xin] > s_x[tou] + E[k].cost && E[k].flow) 63 { 64 s_x[xin] = s_x[tou] + E[k].cost; 65 mer[xin] = k; 66 if(!mark[xin]) 67 { 68 mark[xin] = 1; 69 q.push(xin); 70 if(++C[xin] > n) return xin; 71 } 72 } 73 } 74 } 75 return 0; 76 } 77 78 int main () 79 { 80 int n ,m ,i ,j; 81 int st[N_node]; 82 while(~scanf("%d %d" ,&n ,&m)) 83 { 84 for(i = 1 ;i <= n ;i++) 85 scanf("%d %d %d" ,&A[i].a ,&A[i].b ,&A[i].c); 86 for(i = 1 ;i <= m ;i ++) 87 scanf("%d %d %d" ,&B[i].a ,&B[i].b ,&B[i].c); 88 memset(st ,0 ,sizeof(st)); 89 for(i = 1 ;i <= n ;i ++) 90 for(j = 1 ;j <= m ;j ++) 91 { 92 scanf("%d" ,&now[i][j]); 93 st[j] += now[i][j]; 94 } 95 memset(list ,0 ,sizeof(list)); 96 tot = 1; 97 int ss = 0 ,tt = n + m + 1; 98 for(i = 1 ;i <= n ;i ++) 99 add(ss ,i ,0 ,0),add(i ,ss ,0 ,A[i].c); 100 for(i = 1 ;i <= m ;i ++) 101 add(i + n ,tt ,0 ,B[i].c - st[i]) ,add(tt ,i + n ,0 ,st[i]); 102 for(i = 1 ;i <= n ;i ++) 103 for(j = 1 ;j <= m ;j ++) 104 { 105 add(i ,j + n ,abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1 ,INF - now[i][j]); 106 add(j + n ,i ,-(abss(A[i].a-B[j].a)+abss(A[i].b - B[j].b) + 1) ,now[i][j]); 107 } 108 int x = Spfa(tt ,tt); 109 if(!x) 110 { 111 printf("OPTIMAL\n"); 112 continue; 113 } 114 printf("SUBOPTIMAL\n"); 115 memset(mark ,0 ,sizeof(mark)); 116 i = mer[x]; 117 while(1)//找到一个肯定在环上的点 118 { 119 x = E[i].to; 120 if(mark[x]) break; 121 mark[x] = 1; 122 i = mer[E[i].from]; 123 } 124 memset(mark ,0 ,sizeof(mark)); 125 for(i = mer[x] ;i + 1 ;i = mer[E[i].from]) 126 { 127 int a = E[i].from ,b = E[i].to; 128 if(a >= 1 && a <= n && b >= n + 1 && b <= n + m) 129 now[a][b-n] ++; 130 if(a >= n + 1 && a <= n + m && b >= 1 && b <= n) 131 now[b][a-n] --; 132 if(mark[a] && mark[b]) break; 133 mark[a] = mark[b] = 1; 134 } 135 for(i = 1 ;i <= n ;i ++) 136 for(j = 1 ;j <= m ;j ++) 137 if(j == m) printf("%d\n" ,now[i][j]); 138 else printf("%d " ,now[i][j]); 139 } 140 return 0; 141 142 }
poj 2135
对流量有要求的最小费用最大流
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*Author :usedrose */ 2 /*Created Time :2015/7/27 15:20:54*/ 3 /*File Name :2.cpp*/ 4 #include <cstdio> 5 #include <iostream> 6 #include <algorithm> 7 #include <sstream> 8 #include <cstdlib> 9 #include <cstring> 10 #include <climits> 11 #include <vector> 12 #include <string> 13 #include <ctime> 14 #include <cmath> 15 #include <deque> 16 #include <queue> 17 #include <stack> 18 #include <set> 19 #include <map> 20 #define INF 0x3f3f3f3f 21 #define eps 1e-8 22 #define pi acos(-1.0) 23 #define MAXN 2010 24 #define OK cout << "ok" << endl; 25 #define o(a) cout << #a << " = " << a << endl 26 #define o1(a,b) cout << #a << " = " << a << " " << #b << " = " << b << endl 27 using namespace std; 28 typedef long long LL; 29 30 struct edge { 31 int to, cap, cost, rev; 32 }; 33 34 int V; 35 vector<edge> G[MAXN]; 36 int dist[MAXN]; 37 int prevv[MAXN], preve[MAXN]; 38 39 void add_edge(int from, int to, int cap, int cost) 40 { 41 G[from].push_back({ to, cap, cost, G[to].size() }); 42 G[to].push_back({ from, 0, -cost, G[from].size() - 1 }); 43 } 44 45 //求解从s到t流量为f的最小费用流 46 //不能增广返回-1 47 int min_cost_flow(int s, int t, int f) 48 { 49 int res = 0; 50 while (f > 0) { 51 fill(dist, dist + V, INF); 52 dist[s] = 0; 53 bool update = true; 54 while (update) { 55 update = false; 56 for (int v = 0; v < V; ++v) { 57 if (dist[v] == INF) continue; 58 for (int i = 0; i < G[v].size(); ++i) { 59 edge &e = G[v][i]; 60 if (e.cap > 0 && dist[e.to] > dist[v] + e.cost) { 61 dist[e.to] = dist[v] + e.cost; 62 prevv[e.to] = v; 63 preve[e.to] = i; 64 update = true; 65 } 66 } 67 } 68 } 69 70 71 if (dist[t] == INF) return -1; 72 73 int d = f; 74 for (int v = t; v != s; v = prevv[v]) { 75 d = min(d, G[prevv[v]][preve[v]].cap); 76 } 77 f -= d; 78 res += d*dist[t]; 79 for (int v = t; v != s; v = prevv[v]) { 80 edge &e = G[prevv[v]][preve[v]]; 81 e.cap -= d; 82 G[v][e.rev].cap += d; 83 } 84 } 85 return res; 86 } 87 88 void solve() 89 { 90 int x, y, w, m; 91 cin >> V >> m; 92 int s = 0, t = V - 1; 93 for (int i = 0; i < m; ++i) { 94 cin >> x >> y >> w; 95 x--, y--; 96 add_edge(x, y, 1, w); 97 add_edge(y, x, 1, w); 98 } 99 cout << min_cost_flow(s, t, 2) << endl; 100 } 101 102 int main() 103 { 104 //freopen("data.in","r",stdin); 105 //freopen("data.out","w",stdout); 106 cin.tie(0); 107 ios::sync_with_stdio(false); 108 solve(); 109 return 0; 110 }