网络流24题 (6/21)
来源:互联网 发布:emui8.0 知乎 编辑:程序博客网 时间:2024/06/05 05:14
flag待补全
6/21
提交地址:cogs
- 一般dinic算法求最大流,E-k+bellman求费用流
1. [网络流24题] 搭配飞行员
思路: 二分图最大匹配建图
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>using namespace std;const int maxn = 105,inf = 0x3f3f3f3f;struct node{ int to,next,cap,rev; node(){} node(int a,int b,int c,int d){to = a; next = b; cap = c; rev = d;}}edge[maxn*maxn<<1];int h[maxn],lev[maxn];int n,m,a,b;int num,s,t;void init(){ for(int i = 0; i < maxn; i ++) h[i] = -1; num = 0; s = 0; t = n+1;}void add(int u,int v){ edge[num] = node(v,h[u],1,num+1); h[u] = num++; edge[num] = node(u,h[v],0,num-1); h[v] = num++;}bool bfs(){ for(int i = s; i <= t; i++) lev[i] = -1; lev[s] = 0; queue<int> q; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = h[u] ;~i; i=edge[i].next) { int v = edge[i].to,cap = edge[i].cap; if(lev[v] == -1 && cap) { lev[v] = lev[u] + 1; q.push(v); } } } return lev[t] != -1;}int dfs(int u,int f){ if(u == t) return f; for(int i = h[u]; ~i ; i = edge[i].next) { int v = edge[i].to,cap = edge[i].cap, rev = edge[i].rev; if(lev[v] == lev[u] + 1 && cap) { int k = dfs(v,min(cap,f)); if(!k) continue; edge[i].cap -= k; edge[rev].cap +=k; return k; } } lev[u] = -2; return 0;}void dinic(){ int flow = 0; while(bfs()) { while(int k = dfs(s,inf)) flow += k; } printf("%d\n",flow);}int main(){ freopen("flyer.in","r",stdin); freopen("flyer.out","w",stdout); scanf("%d%d",&n,&m); init(); for(int i = 1; i <= m; i++) add(s,i); while(~scanf("%d%d",&a,&b)) { add(a,b); } for(int i = m+1; i <= n; i++) add(i,t); dinic(); return 0;}
2. [网络流24题] 太空飞行计划
思路:
最大权闭合图,要求输出方案,最后选定的结点就是还存在于残量网络中的,也就是lev[i]还>0 的点
最大权闭合回路连图方案,对所有正权点连图S->v cap为v的值,而对所有负权点连边v->T,cap为负权取反,然后对所有的u>v连边,cap为inf,在这个图上跑最大流,最后的答案就为Sum(val[i]) (val[i]>0)-Max_flow;
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>#include <sstream>using namespace std;const int maxn = 300,inf = 0x3f3f3f3f;struct node{ int to,next,cap,ori,rev; node(){} node(int a,int b,int c,int d,int e){to = a; next = b; cap = c; rev = d;ori = e;}}edge[maxn*maxn];int h[maxn],lev[maxn];int vis[maxn],used[maxn];int num,n,m,s,t;void init(){ memset(h,-1,sizeof(h)); for(int i = 0; i <= max(n,m); i++) vis[i] = used[i] = 0; num = 0; s = 0, t = n+m+1;}void add(int u,int v,int flow){ edge[num] = node(v,h[u],flow,num+1,flow); h[u] = num++; edge[num] = node(u,h[v], 0 , num-1, 0); h[v] = num++;}bool bfs(){ for(int i = s; i <= t; i++) lev[i] = -1; queue<int> q; q.push(s); lev[s] = 0; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = h[u] ;~i; i = edge[i].next) { int v = edge[i].to,cap = edge[i].cap; //cout << v << endl; if(lev[v] == -1 && cap) { lev[v] = lev[u] + 1; q.push(v); } } } return lev[t] != -1;}int dfs(int u,int f){ if(u == t) return f; for(int i = h[u] ;~i ; i = edge[i].next) { int v = edge[i].to,cap = edge[i].cap, rev = edge[i].rev; if(lev[v] == lev[u] + 1 && cap) { int k = dfs(v,min(f,cap)); if(!k) continue; edge[i].cap -= k; edge[rev].cap += k; return k; } } lev[u] = -2; return 0;}int Max_flow(){ int flow = 0; while(bfs()) while(int k = dfs(s,inf)) flow += k; return flow;}char str[1005];int main(){ freopen("shuttle.in","r",stdin); freopen("shuttle.out","w",stdout); int a,b,c; while(~scanf("%d%d",&n,&m)) { init(); int sum = 0; cin.getline(str,1005); for(int i = 1; i <= n; i++) { cin.getline(str,1005); stringstream ss;int temp; ss << str; ss >> temp; sum += temp; add(s,i,temp); while(ss >> temp) add(i, temp+n , inf); } for(int i = 1; i <= m; i++) scanf("%d",&c),add(i+n,t,c); int cnt = Max_flow(); for(int i = 1; i <= n; i++) if(lev[i] > 0) vis[i] = 1; for(int i = 1+n; i <= n+m; i++) if(lev[i] > 0) used[i-n] = 1; int flag = 0,mark = 0; for(int i = 1; i <= n; i++) { if(vis[i]) { if(flag) cout << " "; cout << i; flag = 1; } } cout << endl; for(int i = 1; i <= m; i++) { if(used[i] == 1) { if(mark) cout <<" "; cout << i; mark = 1; } } cout << endl; printf("%d\n", sum - cnt); } return 0;}
3. [网络流24题] 最小路径覆盖问题
思路:
题目给出了思路….
对于求(DAG上的)最小路径覆盖问题,对所有点拆点,然后连边s->v(1->n), cap为1, v+n ->t(1->n),在图中有边的则连边 u->v+n,这里所有边的cap都为1。最后答案为n-Max_flow
这个题目要求输出路径,这里明显匹配了的边都是选定的边,所有我们只需要从头到尾找i->j,j->k,这种就够了。
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>using namespace std;const int maxn = 300 + 5, maxe = maxn*maxn,inf = 0x3f3f3f3f;struct node{ int to,flow,rev,next; node(){} node(int a,int b,int c,int d){to = a;flow = b; rev = c; next = d;} node(int a,int b){to = a;next = b;}}edge[maxe];int h[maxn],e[maxn],vis[maxn];int lev[maxn];int num,m,n,s,t,edgenum;void init(){ num = edgenum = 0; for(int i = 0; i <= 2*n + 1; i++) h[i] = -1,e[i] = -1,vis[i] = 0; s = 0, t = 2*n+1;}void add(int u,int v,int cap){ edge[num] = node(v,cap,num+1,h[u]); h[u] = num++; edge[num] = node(u,0,num-1,h[v]); h[v] = num++;}bool bfs(){ for(int i = s; i <= t; i++) lev[i] = -1; queue<int> q; q.push(s); lev[s] = 0; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = h[u];~i;i = edge[i].next) { int v = edge[i].to,cap = edge[i].flow; if(lev[v] == -1 && cap) { lev[v] = lev[u] + 1; q.push(v); } } } return lev[t] != -1;}int dfs(int u,int f){ if(u ==t )return f; for(int i = h[u] ;~i; i =edge[i].next) { int v = edge[i].to, flow = edge[i].flow,rev = edge[i].rev; if(lev[v] == lev[u] + 1 && flow) { int k = dfs(v, min (f,flow)); if(!k) continue; edge[i].flow -= k; edge[rev].flow += k; return k; } } lev[u] = -2; return 0;}void Find(int u,int ori){ vis[u] = 1; if(u == ori) cout << u; else cout << " " << u; if(e[u] != -1) Find(e[u],ori);}void Max_flow(){ int flow = 0,cnt = 0; while(bfs()) while(int k = dfs(s,inf)) flow += k; //cout << flow << endl; for(int u = 1; u <= n; u++) for(int i = h[u] ; ~i; i = edge[i].next) { int v = edge[i].to, flow = edge[i].flow; if(v <= 2*n && v > n && flow == 0) e[u] = v-n; } for(int i = 1; i <= n; i++) { if(!vis[i]) {cnt++,Find(i,i);cout << endl;} } printf("%d\n",cnt);}int main(){ freopen("path3.in","r",stdin); freopen("path3.out","w",stdout); int a,b,c; while(~scanf("%d%d",&n,&m)) { init(); for(int i = 1; i <= n; i++) add(s,i,1); for(int i = 0; i < m; i++) scanf("%d%d",&a,&b),add(a,b+n,1); for(int i = n+1 ; i <= n*2 ; i++) add(i,t,1); Max_flow(); } return 0;}
4. [网络流24题]魔术球问题(简化版
思路: 可以看作i与j有边(满足i+j为一个完全平方数),所以这个题也可以看作上一题的最小路径覆盖问题。
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <cmath>using namespace std;const int maxn = 3205,maxe = 1e6,inf = 0x3f3f3f3f;struct node{ int to,cap,rev,next; node(){} node(int a,int b,int c,int d){to = a; cap = b; rev = c; next = d;}}edge[maxe<<1];int num,s,t,n;int h[maxn],lev[maxn];int ans[61];void add(int u,int v,int cap){ edge[num] = node(v,cap,num+1,h[u]); h[u] = num++; edge[num] = node(u,0,num - 1,h[v]); h[v] = num++;}void init(){ for(int i = 0; i < maxn; i++) h[i] = -1; s = num = 0;}bool bfs(){ for(int i = 0; i <= t; i++) lev[i] = -1; queue<int> q; q.push(s); lev[s] = 0; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = h[u] ;~i; i = edge[i].next) { int v = edge[i].to,cap = edge[i].cap; if(lev[v] == -1 && cap) { lev[v] = lev[u] + 1; q.push(v); } } } return lev[t] != -1;}int dfs(int u,int f){ if(u == t) return f; for(int i = h[u] ;~i; i = edge[i].next) { int v = edge[i].to,cap = edge[i].cap, rev = edge[i].rev; if(lev[v] == lev[u] + 1 && cap) { int k = dfs(v,min(cap,f)); if(!k) continue; edge[i].cap -= k; edge[rev].cap += k; return k; } } lev[u] = -2; return 0;}int Max_flow(){ int flow = 0; while(bfs()) { while(int k = dfs(s,inf)) flow += k; } return flow;}int main(){ freopen("balla.in","r",stdin); freopen("balla.out","w",stdout); t = 1600*2+1; init(); int temp=0; for(int i = 1; i <= 1600; i++) { add(s,i,1); add(i+1600,t,1); for(int j = 1; j < i; j++) { int th = sqrt(i+j); if(th*th == (i+j)) add(j,i+1600,1); } temp += Max_flow(); ans[i-temp] = i; } while(~scanf("%d",&n)) printf("%d\n",ans[n]); return 0;}
5. [网络流24题] 圆桌聚餐
思路: 这个感觉就是直接连边……最后找一找残量网络中那些由不同单位到餐桌上flow为0的边,这代表这个单位到这个餐桌有一个代表。
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>using namespace std;const int N = 150+5, M = 270+5, maxn = N+M, inf = 0x3f3f3f3f;struct node{ int to,next,cap,rev; node(){} node(int a,int b,int c,int d){to = a; next = b; cap = c; rev = d;}}edge[maxn*maxn];//int ans[maxn];int lev[maxn];int h[maxn];int num,s,t, n,m,sum;void init(){ for(int i = 0; i < (n+m)+2; i++) h[i] = -1; num = 0; s = 0, t = n+m+1; sum = 0;}bool bfs(){ for(int i = s; i <= t; i++) lev[i] = -1; lev[0] = 0; queue<int> q; q.push(0); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = h[u]; ~i; i = edge[i].next) { int v = edge[i].to,cap = edge[i].cap; if(lev[v] == -1 && cap) { lev[v] = lev[u] + 1; q.push(v); } } } return lev[t] != -1;}int dfs(int u,int f){ if(u==t) return f; for(int i = h[u]; ~i ; i = edge[i].next) { int v = edge[i].to,cap = edge[i].cap, rev = edge[i].rev; if(lev[v] == lev[u] + 1 && cap) { int k = dfs(v,min(f,cap)); if(!k) continue; edge[i].cap -= k; edge[rev].cap += k; return k; } } lev[u] = -2; return 0;}void add(int u,int v,int cap){ edge[num] = node(v,h[u],cap,num+1); h[u] = num++; edge[num] = node(u,h[v],0,num-1); h[v] = num++;}void solve(){ int flow = 0; while(bfs()) while(int k = dfs(0,inf)) flow += k; if(flow != sum) printf("0\n"); else { printf("1\n"); for(int u = 1; u <= n; u++) { int flag = 0; for(int i = h[u] ;~i; i = edge[i].next) { int v = edge[i].to, cap = edge[i].cap; if(cap == 0) { if(flag) printf(" "); printf("%d",v-n); flag = 1; } } printf("\n"); } }}int main(){ freopen("roundtable.in","r",stdin); freopen("roundtable.out","w",stdout); int a; while(~scanf("%d%d",&n,&m)) { init(); for(int i = 1; i <= n; i++) scanf("%d",&a), add(s,i,a), sum += a; for(int i = 1; i <= m; i++) scanf("%d",&a), add(n+i,t,a); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) add(i,n+j,1); solve(); } return 0;}
6. [网络流24题] 运输问题
思路: 这个连边就是直接连,然后求一遍最小费用流,我在求最大费用的时候是把d[i]置成-inf,然后求的最长路。
代码:
//求最大费用流与最小费用流#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>using namespace std;#define ll long longconst int inf = 0x3f3f3f3f,maxn = 200 + 10,maxe = 2e4 + 10;struct node{ int to,cap,w,rev,next,from; node(){} node(int a,int b,int c,int d,int e,int f) {to = a; cap = b; w = c; rev = d; next = e;from = f;}}edge[maxe<<1],edge1[maxe << 1];int h[maxn],h1[maxn],d[maxn],a[maxn],inq[maxn],pre[maxn];int num,num1,s,t,n,m;void init(){ s = num = num1 = 0; t = n+m+1; for(int i = 0; i < maxn; i++) h[i] = h1[i] = -1;}void add(int u,int v,int cap,int w){ edge[num] = node(v,cap,w,num+1,h[u],u); h[u] = num++; edge[num] = node(u,0,-w,num-1, h[v],v); h[v] = num++; edge1[num1] = node(v,cap,w,num1+1,h1[u],u); h1[u] = num1++; edge1[num1] = node(u,0,-w,num1-1, h1[v],v); h1[v] = num1++;}int bfs(){ for(int i = 0; i < maxn ; i++) d[i] = inf, a[i] = 0, inq[i] = 0; queue<int> q; q.push(0); d[0] = 0, a[0] = inf, inq[0] = 1; while(!q.empty()) { int u = q.front(); q.pop(); inq[u] = 0; for(int i = h[u] ;~i; i = edge[i].next) { int v = edge[i].to, cap = edge[i].cap,w = edge[i].w; if(cap && d[v] > d[u] + w) { d[v] = d[u] + w; a[v] = min(a[u], cap); pre[v] = i; if(!inq[v]){q.push(v); inq[v] = 1;} } } } if(d[t] == inf) return 0; for(int u = t; u != s; u = edge[pre[u]].from) { int rev = edge[pre[u]].rev; edge[pre[u]].cap -= a[t]; edge[rev].cap += a[t]; } return d[t]*a[t];}int bfs1(){ for(int i = 0; i < maxn ; i++) d[i] = -inf, a[i] = 0, inq[i] = 0; queue<int> q; q.push(0); d[0] = 0, a[0] = inf, inq[0] = 1; while(!q.empty()) { int u = q.front(); q.pop(); inq[u] = 0; for(int i = h1[u] ;~i; i = edge1[i].next) { int v = edge1[i].to, cap = edge1[i].cap , w = edge1[i].w; if(cap && d[v] < d[u] + w) { d[v] = d[u] + w; a[v] = min(a[u], cap); pre[v] = i; if(!inq[v]){q.push(v); inq[v] = 1;} } } } if(d[t] == -inf) return 0; for(int u = t; u != s; u = edge1[pre[u]].from) { int rev = edge1[pre[u]].rev; edge1[pre[u]].cap -= a[t]; edge1[rev].cap += a[t]; } return d[t]*a[t];}void E_K1(){ ll res = 0; while(int k = bfs()) res += k; printf("%lld\n",res);}void E_K2(){ ll res = 0; while(int k = bfs1()) res += k; printf("%lld\n",res);}int main(){ freopen("tran.in","r",stdin); freopen("tran.out","w",stdout); int a; scanf("%d%d",&n,&m); init(); for(int i = 1; i <= n; i++)scanf("%d",&a), add(s,i,a,0); for(int i = 1; i <= m; i++)scanf("%d",&a), add(i+n,t,a,0); for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++)scanf("%d",&a),add(i,j+n,inf,a); E_K1(); E_K2(); return 0;}
阅读全文
0 0
- 网络流24题 (6/21)
- 网络流24题-6
- 【网络流】网络流24题
- [网络流]: 网络流24题
- 网络流24题
- 网络流24题
- 网络流24题
- 网络流24题
- 网络流24题---餐巾纸
- [网络流24题] 餐巾
- 网络流24题-2
- 网络流24题-3
- 网络流24题-4
- 网络流24题-5
- 网络流24题-7
- 网络流24题-8
- 网络流24题-9
- 网络流24题-11
- keepalived+nginx实现高可用(二)
- JAVA CAS原理深度分析
- 可移植的oat文件
- 干货5:顺序队列
- pyspider 控制台说明
- 网络流24题 (6/21)
- 两端都是圆角的进度条和动态进度条
- Kafka数据可靠性与一致性解析
- 浅析Android权限机制(一) —— Android的权限机制
- sat-ip from wikipedia
- 在Android项目中使用FCM(FirebaeCloudMessage)
- java 用pdfbox读取pdf
- Android中ViewPager常用功能7----画廊效果
- Eclipse配置Python+Pydev