学会了网络流,就经常闲的没事儿刷网络流……于是乎来一发题解。

1. COGS2093 花园的守护之神

题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长。

用Dijkstra或者SPFA跑出来s-t最短路,然后把最短路DAG上的每条边的容量设为1,跑最小割即可。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #define INF ((~((1)<<(31)))>>(1))
  6. using namespace std;
  7. const int maxn=,maxe=;
  8. struct edge1{int from,to,prev;long long dis;}e1[maxe<<];
  9. struct edge2{int to,cap,prev;}e2[maxe<<];
  10. struct node{
  11. int x;
  12. long long dis;
  13. node(int x,long long dis):x(x),dis(dis){}
  14. bool operator<(const node &a)const{return dis>a.dis;}
  15. };
  16. void addedge1(int,int,long long);
  17. void addedge2(int,int,int);
  18. void Dijkstra(int,long long*);
  19. int Dinic();
  20. void bfs();
  21. int dfs(int,int);
  22. int n,m,s,t,last1[maxn]={},len1=,last2[maxn],len2=,now[maxn],d[maxn],q[maxn],head,tail,x,y;
  23. long long dis[maxn],redis[maxn],z;
  24. bool vis[maxn];
  25. int main(){
  26. #define MINE
  27. #ifdef MINE
  28. freopen("greendam2002.in","r",stdin);
  29. freopen("greendam2002.out","w",stdout);
  30. #endif
  31. memset(last2,-,sizeof(last2));
  32. scanf("%d%d%d%d",&n,&m,&s,&t);
  33. for(int i=;i<=m;i++){
  34. scanf("%d%d%lld",&x,&y,&z);
  35. addedge1(x,y,z);
  36. addedge1(y,x,z);
  37. }
  38. Dijkstra(s,dis);
  39. Dijkstra(t,redis);
  40. for(int i=;i<=(m<<);i++)if(dis[e1[i].from]+e1[i].dis+redis[e1[i].to]==dis[t]){
  41. addedge2(e1[i].from,e1[i].to,);
  42. addedge2(e1[i].to,e1[i].from,);
  43. }
  44. printf("%d",Dinic());
  45. #ifndef MINE
  46. printf("\n--------------------DONE--------------------\n");
  47. for(;;);
  48. #endif
  49. return ;
  50. }
  51. void addedge1(int x,int y,long long z){
  52. e1[++len1].from=x;
  53. e1[len1].to=y;
  54. e1[len1].dis=z;
  55. e1[len1].prev=last1[x];
  56. last1[x]=len1;
  57. }
  58. void addedge2(int x,int y,int z){
  59. e2[len2].to=y;
  60. e2[len2].cap=z;
  61. e2[len2].prev=last2[x];
  62. last2[x]=len2++;
  63. }
  64. void Dijkstra(int x,long long *dis){
  65. memset(vis,,sizeof(vis));
  66. priority_queue<node>q;
  67. memset(dis,,sizeof(long long)*maxn);
  68. dis[x]=;
  69. q.push(node(x,));
  70. while(!q.empty()){
  71. x=q.top().x;
  72. q.pop();
  73. if(vis[x])continue;
  74. vis[x]=true;
  75. for(int i=last1[x];i;i=e1[i].prev)if(dis[e1[i].to]>dis[x]+e1[i].dis){
  76. dis[e1[i].to]=dis[x]+e1[i].dis;
  77. q.push(node(e1[i].to,dis[e1[i].to]));
  78. }
  79. }
  80. }
  81. int Dinic(){
  82. int ans=;
  83. for(;;){
  84. bfs();
  85. if(d[t]==INF)break;
  86. memset(now,,sizeof(now));
  87. ans+=dfs(s,INF);
  88. }
  89. return ans;
  90. }
  91. void bfs(){
  92. int x;
  93. fill_n(d+,n,INF);
  94. d[s]=;
  95. head=tail=;
  96. q[tail++]=s;
  97. while(head!=tail){
  98. x=q[head++];
  99. for(int i=last2[x];i!=-;i=e2[i].prev)if(e2[i].cap>&&d[e2[i].to]==INF){
  100. d[e2[i].to]=d[x]+;
  101. q[tail++]=e2[i].to;
  102. }
  103. }
  104. }
  105. int dfs(int x,int delta){
  106. if(x==t||!delta)return delta;
  107. int flow=,f;
  108. for(int i=(now[x]?e2[now[x]].prev:last2[x]);i!=-;i=e2[i].prev)if(e2[i].cap>&&d[e2[i].to]==d[x]+){
  109. now[x]=i;
  110. f=dfs(e2[i].to,min(delta,e2[i].cap));
  111. if(!f)continue;
  112. e2[i].cap-=f;
  113. e2[i^].cap+=f;
  114. flow+=f;
  115. delta-=f;
  116. if(!delta)break;
  117. }
  118. return flow;
  119. }

2. [NEERC 2003][POJ2125]有向图破坏

题意:给定一个有向图,可以删除一个点所有的出边,费用为wi;或者删除一个点所有的入边,费用为wi’,求把所有边都删掉所需的最少费用。

把点拆成出点和入点,有向边变成连接出点和入点的边,然后就是二分图最小权点覆盖问题。

其实这不是费用流,直接把s到出点和入点到t的边的容量设为对应的费用,其他边容量正无穷,再跑最大流就行。至于为什么,因为这是最小割,不是最小费用最大流。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #define INF (0x3f3f3f3f)
  6. using namespace std;
  7. const int maxn=<<,maxe=;
  8. struct edge{int to,cap,cost,prev;}e[maxe];
  9. void addedge(int,int,int);
  10. void insert(int,int,int);
  11. int Dinic();
  12. void bfs();
  13. int dfs(int,int);
  14. int n,m,s,t,last[maxn],len=,d[maxn],now[maxn],q[maxn],head,tail,tmp,x,y;
  15. int main(){
  16. #define MINE
  17. #ifdef MINE
  18. freopen("destroyingthegraph.in","r",stdin);
  19. freopen("destroyingthegraph.out","w",stdout);
  20. #endif
  21. memset(last,-,sizeof(last));
  22. scanf("%d%d",&n,&m);
  23. s=(n<<)+;
  24. t=s+;
  25. for(int i=;i<=n;i++){
  26. scanf("%d",&tmp);
  27. addedge(i+n,t,tmp);
  28. }
  29. for(int i=;i<=n;i++){
  30. scanf("%d",&tmp);
  31. addedge(s,i,tmp);
  32. }
  33. while(m--){
  34. scanf("%d%d",&x,&y);
  35. addedge(x,y+n,INF);
  36. }
  37. printf("%d",Dinic());
  38. #ifndef MINE
  39. printf("\n-------------------------DONE-------------------------\n");
  40. for(;;);
  41. #endif
  42. return ;
  43. }
  44. void addedge(int x,int y,int z){
  45. insert(x,y,z);
  46. insert(y,x,);
  47. }
  48. void insert(int x,int y,int z){
  49. e[len].to=y;
  50. e[len].cap=z;
  51. e[len].prev=last[x];
  52. last[x]=len++;
  53. }
  54. int Dinic(){
  55. int ans=;
  56. for(;;){
  57. bfs();
  58. if(d[t]==INF)break;
  59. memset(now,,sizeof(now));
  60. ans+=dfs(s,INF);
  61. }
  62. return ans;
  63. }
  64. void bfs(){
  65. int x;
  66. memset(d,,sizeof(d));
  67. d[s]=;
  68. head=tail=;
  69. q[tail++]=s;
  70. while(head!=tail){
  71. x=q[head++];
  72. for(int i=last[x];i!=-;i=e[i].prev)if(e[i].cap>&&d[e[i].to]>d[x]+){
  73. d[e[i].to]=d[x]+;
  74. q[tail++]=e[i].to;
  75. }
  76. }
  77. }
  78. int dfs(int x,int delta){
  79. if(x==t||!delta)return delta;
  80. int flow=,f;
  81. for(int i=(now[x]?e[now[x]].prev:last[x]);i!=-;i=e[i].prev)if(e[i].cap>&&d[e[i].to]==d[x]+){
  82. now[x]=i;
  83. f=dfs(e[i].to,min(delta,e[i].cap));
  84. if(!f)continue;
  85. e[i].cap-=f;
  86. e[i^].cap+=f;
  87. flow+=f;
  88. delta-=f;
  89. if(!delta)break;
  90. }
  91. return flow;
  92. }

3. [SGU252]铁路网

题意略,总之就是带边权的最小路径覆盖问题。

拆二分图,连带费用的边,然后一发最小费用最大流就行。必须最大流的原因在于这是最少路径条数覆盖,所以必须增广到最大流才能保证所求出的是最小路径覆盖。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. using namespace std;
  6. const int maxn=,maxe=;
  7. struct edge{int to,cap,cost,prev;}e[maxe<<];
  8. void addedge(int,int,int,int);
  9. void insert(int,int,int,int);
  10. void mincostmaxflow();
  11. void SPFA();
  12. int n,m,last[maxn],len=,dis[maxn],p[maxn],s,t,flow=,cost=,x,y,z;
  13. bool inq[maxn];
  14. int main(){
  15. #define MINE
  16. #ifdef MINE
  17. freopen("railwaycommunication.in","r",stdin);
  18. freopen("railwaycommunication.out","w",stdout);
  19. #endif
  20. memset(last,-,sizeof(last));
  21. scanf("%d%d",&n,&m);
  22. s=(n<<|);
  23. t=s+;
  24. for(int i=;i<=n;i++){
  25. addedge(s,i,,);
  26. addedge(i+n,t,,);
  27. }
  28. while(m--){
  29. scanf("%d%d%d",&x,&y,&z);
  30. addedge(x,y+n,,z);
  31. }
  32. mincostmaxflow();
  33. printf("%d %d",n-flow,cost);
  34. #ifndef MINE
  35. printf("\n-------------------------DONE-------------------------\n");
  36. for(;;);
  37. #endif
  38. return ;
  39. }
  40. void addedge(int x,int y,int z,int w){
  41. insert(x,y,z,w);
  42. insert(y,x,,-w);
  43. }
  44. void insert(int x,int y,int z,int w){
  45. e[len].to=y;
  46. e[len].cap=z;
  47. e[len].cost=w;
  48. e[len].prev=last[x];
  49. last[x]=len++;
  50. }
  51. void mincostmaxflow(){
  52. int delta,x;
  53. for(;;){
  54. SPFA();
  55. if(dis[t]==0x3f3f3f3f)break;
  56. delta=~(<<);
  57. for(x=t;x!=s;x=e[p[x]^].to)delta=min(delta,e[p[x]].cap);
  58. for(x=t;x!=s;x=e[p[x]^].to){
  59. e[p[x]].cap-=delta;
  60. e[p[x]^].cap+=delta;
  61. cost+=e[p[x]].cost*delta;
  62. }
  63. flow+=delta;
  64. }
  65. }
  66. void SPFA(){
  67. int x;
  68. memset(dis,,sizeof(dis));
  69. memset(inq,,sizeof(inq));
  70. queue<int>q;
  71. q.push(s);
  72. dis[s]=;
  73. while(!q.empty()){
  74. x=q.front();
  75. q.pop();
  76. inq[x]=false;
  77. for(int i=last[x];i!=-;i=e[i].prev)if(e[i].cap>&&dis[e[i].to]>dis[x]+e[i].cost){
  78. dis[e[i].to]=dis[x]+e[i].cost;
  79. p[e[i].to]=i;
  80. if(!inq[e[i].to]){
  81. inq[e[i].to]=true;
  82. q.push(e[i].to);
  83. }
  84. }
  85. }
  86. }

4. [ZJOI2010]网络扩容

题意:给定一张有向图,每条边都有一个容量C和一个将容量扩大1所需的费用W。求在不扩容的情况下,1到N的最大流和将1到N的最大流增加K所需的最小扩容费用。

每条边拆成两条边,一条容量为C费用为0,一条容量正无穷费用为W,然后跑费用为0时的最大流,再在残量网络上跑固定流量最小费用流即可。

一开始的最大流可以用Dinic之类的算法写,(懒得再写一份最大流的)也可以用费用流代替,只要在费用增大到大于0之前记录流量即可。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<deque>
  5. using namespace std;
  6. const int maxn=,maxe=;
  7. struct edge{int to,cap,cost,prev;}e[maxn<<];
  8. void addedge(int,int,int,int);
  9. void insert(int,int,int,int);
  10. int Dinic();
  11. void bfs();
  12. int dfs(int,int);
  13. int mincostflow();
  14. void SPFA();
  15. int n,m,k,last[maxn],len=,s,t,dis[maxn],now[maxn],q[maxn],head,tail,p[maxn],x,y,z,w;
  16. bool inq[maxn];
  17. int main(){
  18. #define MINE
  19. #ifdef MINE
  20. freopen("networkzj2010.in","r",stdin);
  21. freopen("networkzj2010.out","w",stdout);
  22. #endif
  23. memset(last,-,sizeof(last));
  24. scanf("%d%d%d",&n,&m,&k);
  25. s=;
  26. t=n;
  27. while(m--){
  28. scanf("%d%d%d%d",&x,&y,&z,&w);
  29. addedge(x,y,z,);
  30. addedge(x,y,0x3f3f3f3f,w);
  31. }
  32. printf("%d ",Dinic());
  33. printf("%d",mincostflow());
  34. #ifndef MINE
  35. printf("\n-------------------------DONE-------------------------\n");
  36. for(;;);
  37. #endif
  38. return ;
  39. }
  40. void addedge(int x,int y,int z,int w){
  41. insert(x,y,z,w);
  42. insert(y,x,,-w);
  43. }
  44. void insert(int x,int y,int z,int w){
  45. e[len].to=y;
  46. e[len].cap=z;
  47. e[len].cost=w;
  48. e[len].prev=last[x];
  49. last[x]=len++;
  50. }
  51. int Dinic(){
  52. int ans=;
  53. for(;;){
  54. bfs();
  55. if(dis[t]==0x3f3f3f3f)break;
  56. memset(now,,sizeof(now));
  57. ans+=dfs(s,~(<<));
  58. }
  59. return ans;
  60. }
  61. void bfs(){
  62. int x;
  63. memset(dis,,sizeof(dis));
  64. dis[s]=;
  65. head=tail=;
  66. q[tail++]=s;
  67. while(head!=tail){
  68. x=q[head++];
  69. for(int i=last[x];i!=-;i=e[i].prev)if(!e[i].cost&&e[i].cap>&&dis[e[i].to]>dis[x]+){
  70. dis[e[i].to]=dis[x]+;
  71. q[tail++]=e[i].to;
  72. }
  73. }
  74. }
  75. int dfs(int x,int delta){
  76. if(x==t||!delta)return delta;
  77. int flow=,f;
  78. for(int i=(now[x]?e[now[x]].prev:last[x]);i!=-;i=e[i].prev)if(!e[i].cost&&e[i].cap>&&dis[e[i].to]==dis[x]+){
  79. now[x]=i;
  80. f=dfs(e[i].to,min(delta,e[i].cap));
  81. if(!f)continue;
  82. e[i].cap-=f;
  83. e[i^].cap+=f;
  84. flow+=f;
  85. delta-=f;
  86. if(!delta)break;
  87. }
  88. return flow;
  89. }
  90. int mincostflow(){
  91. int ans=,x,delta;
  92. for(;;){
  93. SPFA();
  94. if(dis[t]==0x3f3f3f3f)break;
  95. delta=k;
  96. for(x=t;x!=s;x=e[p[x]^].to)delta=min(delta,e[p[x]].cap);
  97. for(x=t;x!=s;x=e[p[x]^].to){
  98. e[p[x]].cap-=delta;
  99. e[p[x]^].cap+=delta;
  100. ans+=e[p[x]].cost*delta;
  101. }
  102. k-=delta;
  103. if(!k)break;
  104. }
  105. return ans;
  106. }
  107. void SPFA(){
  108. int x;
  109. memset(dis,,sizeof(dis));
  110. memset(inq,,sizeof(inq));
  111. deque<int>q;
  112. q.push_back(s);
  113. dis[s]=;
  114. while(!q.empty()){
  115. x=q.front();
  116. q.pop_front();
  117. inq[x]=false;
  118. for(int i=last[x];i!=-;i=e[i].prev)if(e[i].cap>&&dis[e[i].to]>dis[x]+e[i].cost){
  119. dis[e[i].to]=dis[x]+e[i].cost;
  120. p[e[i].to]=i;
  121. if(!inq[e[i].to]){
  122. inq[e[i].to]=true;
  123. if(!q.empty()&&dis[e[i].to]<dis[q.front()])q.push_front(e[i].to);
  124. else q.push_back(e[i].to);
  125. }
  126. }
  127. }
  128. }

5. 最小最大生成树

题意:给定一个带权无向连通图,求使得加入的权值为w的边(u,v)既能出现在最小生成树上也能出现在最大生成树上所需要删除的最少边数。

一条权为w的边(u,v)不能出现在最小生成树上的充要条件是u,v可以只借助边权<w的边而连通,所以直接把边权<w的所有边扔进图里,容量为1,然后跑u-v最小割即可。最大生成树同理。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define INF (0x3f3f3f3f)
  5. using namespace std;
  6. const int maxn=,maxe=;
  7. struct edge1{int from,to,w;}ee[maxe];
  8. struct edge{int to,cap,prev;}e[maxe<<];
  9. void addedge(int,int,int);
  10. int Dinic();
  11. void bfs();
  12. int dfs(int,int);
  13. int n,m,last[maxn],len=,d[maxn],now[maxn],q[maxn],head,tail,s,t,w,ans=;
  14. int main(){
  15. #define MINE
  16. #ifdef MINE
  17. freopen("mstmn.in","r",stdin);
  18. freopen("mstmn.out","w",stdout);
  19. #endif
  20. scanf("%d%d",&n,&m);
  21. for(int i=;i<=m;i++)scanf("%d%d%d",&ee[i].from,&ee[i].to,&ee[i].w);
  22. scanf("%d%d%d",&s,&t,&w);
  23. memset(last,-,sizeof(last));
  24. for(int i=;i<=m;i++)if(ee[i].w<w){
  25. addedge(ee[i].from,ee[i].to,);
  26. addedge(ee[i].to,ee[i].from,);
  27. }
  28. ans+=Dinic();
  29. memset(last,-,sizeof(last));
  30. len=;
  31. for(int i=;i<=m;i++)if(ee[i].w>w){
  32. addedge(ee[i].from,ee[i].to,);
  33. addedge(ee[i].to,ee[i].from,);
  34. }
  35. ans+=Dinic();
  36. printf("%d",ans);
  37. #ifndef MINE
  38. printf("\n-------------------------DONE-------------------------\n");
  39. for(;;);
  40. #endif
  41. return ;
  42. }
  43. void addedge(int x,int y,int z){
  44. e[len].to=y;
  45. e[len].cap=z;
  46. e[len].prev=last[x];
  47. last[x]=len++;
  48. }
  49. int Dinic(){
  50. int ans=;
  51. for(;;){
  52. bfs();
  53. if(d[t]==INF)break;
  54. memset(now,,sizeof(now));
  55. ans+=dfs(s,INF);
  56. }
  57. return ans;
  58. }
  59. void bfs(){
  60. int x;
  61. memset(d,,sizeof(d));
  62. head=tail=;
  63. q[tail++]=s;
  64. d[s]=;
  65. while(head!=tail){
  66. x=q[head++];
  67. for(int i=last[x];i!=-;i=e[i].prev)if(e[i].cap>&&d[e[i].to]>d[x]+){
  68. d[e[i].to]=d[x]+;
  69. q[tail++]=e[i].to;
  70. }
  71. }
  72. }
  73. int dfs(int x,int delta){
  74. if(x==t||!delta)return delta;
  75. int flow=,f;
  76. for(int i=(now[x]?e[now[x]].prev:last[x]);i!=-;i=e[i].prev)if(e[i].cap>&&d[e[i].to]==d[x]+){
  77. now[x]=i;
  78. f=dfs(e[i].to,min(delta,e[i].cap));
  79. if(!f)continue;
  80. e[i].cap-=f;
  81. e[i^].cap+=f;
  82. flow+=f;
  83. delta-=f;
  84. if(!delta)break;
  85. }
  86. return flow;
  87. }

6. [网络流24题]餐巾

题意略。

把每天拆成早上和晚上两个点,再新增一个源点s(可以理解为卖餐巾的地方……),从s到每个早上连一条费用为买餐巾费用,容量正无穷的边,从每天早上到晚上连一条流量下界为所需餐巾数的边,从每天晚上向往后a天的早上连费用为快洗费用,流量正无穷的边,慢洗同理。再从每天晚上到后一天晚上连一条费用为0容量正无穷的边,表示餐巾没用上留到明天晚上。这样建图之后可以把每个流量理解为一条餐巾(到处流的餐巾……),那么要求的就是满足那些下界的最小费用可行流。

带下界这个问题也很好说,把它的费用改成负无穷,容量为它的下界,那么跑最小费用流增广的时候一定会增广完它之后才会停止,所以这样转换之后可以保证所有下限都能够被满足。最后把费用减去这一堆负无穷即可。

其实三分贪心比起费用流来说又好写又快……

这份代码是我费用流没学好的时候写的,用的是dfs增广……Too young too simple……

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #define LL long long
  6. #define INF ((~(1<<31))>>1)
  7. using namespace std;
  8. const int maxn=<<;
  9. struct edge{int to,cap,prev;LL cost;}e[];
  10. void addedge(int,int,int,LL);
  11. void insert(int,int,int,LL);
  12. void mincostflow();
  13. void SPFA();
  14. int dfs(int,int);
  15. int last[maxn],len=,now[maxn];
  16. bool inq[maxn];
  17. int n,a,b,s,t;
  18. LL ca,cb,cc,c[maxn],dis[maxn],ans=0ll;
  19. int main(){
  20. freopen("napkin.in","r",stdin);
  21. freopen("napkin.out","w",stdout);
  22. memset(last,-,sizeof(last));
  23. scanf("%d",&n);
  24. a++;b++;
  25. s=(n<<|);t=s+;
  26. for(int i=;i<=n;i++)scanf("%lld",&c[i]);
  27. scanf("%lld%d%lld%d%lld",&cc,&a,&ca,&b,&cb);
  28. for(int i=;i<=n;i++){
  29. ans+=c[i]*INF;
  30. addedge(s,i,INF,cc);
  31. addedge(i,i+n,c[i],-INF);
  32. if(i<n)addedge(i+n,i+n+,INF,);
  33. if(i+a<=n)addedge(i+n,i+a,INF,ca);
  34. if(i+b<=n)addedge(i+n,i+b,INF,cb);
  35. }
  36. t=n+n;
  37. mincostflow();
  38. printf("%lld",ans);
  39. fclose(stdin);
  40. fclose(stdout);
  41. return ;
  42. }
  43. void addedge(int x,int y,int z,LL w){
  44. //printf("addedge(%d,%d,%d,%lld)\n",x,y,z,w);
  45. insert(x,y,z,w);
  46. insert(y,x,,-w);
  47. }
  48. void insert(int x,int y,int z,LL w){
  49. e[len].to=y;
  50. e[len].cap=z;
  51. e[len].cost=w;
  52. e[len].prev=last[x];
  53. last[x]=len++;
  54. }
  55. void mincostflow(){
  56. for(;;){
  57. SPFA();
  58. if(dis[t]>=0ll)break;
  59. memset(now,,sizeof(now));
  60. dfs(s,INF);
  61. }
  62. }
  63. void SPFA(){
  64. int x;
  65. memset(inq,,sizeof(inq));
  66. memset(dis,,sizeof(dis));
  67. queue<int>q;
  68. q.push(s);
  69. dis[s]=;
  70. while(!q.empty()){
  71. x=q.front();
  72. q.pop();
  73. inq[x]=false;
  74. for(int i=last[x];i!=-;i=e[i].prev)if(e[i].cap>&&dis[e[i].to]>dis[x]+e[i].cost){
  75. dis[e[i].to]=dis[x]+e[i].cost;
  76. if(!inq[e[i].to]){
  77. inq[e[i].to]=true;
  78. q.push(e[i].to);
  79. }
  80. }
  81. }
  82. }
  83. int dfs(int x,int delta){
  84. if(x==t||!delta)return delta;
  85. int f;
  86. for(int i=(now[x]?e[now[x]].prev:last[x]);i!=-;i=e[i].prev)if(e[i].cap>&&dis[e[i].to]==dis[x]+e[i].cost){
  87. now[x]=i;
  88. f=dfs(e[i].to,min(delta,e[i].cap));
  89. if(!f)continue;
  90. e[i].cap-=f;
  91. e[i^].cap+=f;
  92. ans+=e[i].cost*(LL)f;
  93. return f;
  94. }
  95. return ;
  96. }

7. COGS1632 搬运工

题意略,带权二分图点覆盖。

为了保证次数最小,把边权统一加上100000,然后跑最大流即可。最后的最小次数是流量/100000,最少费用是流量%100000。

不得不说这个建图比较机智……其实也是用大的屏蔽小的来实现优先级之类的玩意儿。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int maxn=;
  6. struct edge{int to,prev,cap;}e[maxn*maxn<<];
  7. void addedge(int,int,int);
  8. void AddEdge(int,int,int);
  9. int Dinic();
  10. void bfs(int);
  11. int dfs(int,int);
  12. int last[maxn],d[maxn],now[maxn],q[maxn];
  13. int n,len=,head,tail,s,t,tmp;
  14. char c;
  15. inline int MAIN(){
  16. #define MINE
  17. #ifdef MINE
  18. freopen("worker.in","r",stdin);
  19. freopen("worker.out","w",stdout);
  20. #endif
  21. memset(last,-,sizeof(last));
  22. scanf("%d",&n);
  23. for(int i=;i<=n;i++)for(int j=;j<=n;j++){
  24. scanf(" %c",&c);
  25. if(c=='*')addedge(i,j+n,(~(<<))>>);
  26. }
  27. s=n<<|;t=s+;
  28. for(int i=;i<=n;i++){
  29. scanf("%d",&tmp);
  30. addedge(s,i,tmp+);
  31. }
  32. for(int i=;i<=n;i++){
  33. scanf("%d",&tmp);
  34. addedge(i+n,t,tmp+);
  35. }
  36. n=(n<<)+;
  37. tmp=Dinic();
  38. printf("%d %d",tmp/,tmp%);
  39. #ifndef MINE
  40. printf("\n-------------------------DONE-------------------------\n");
  41. for(;;);
  42. #endif
  43. return ;
  44. }
  45. int hzoier=MAIN();
  46. int main(){;}
  47. void addedge(int x,int y,int z){
  48. AddEdge(x,y,z);
  49. AddEdge(y,x,);
  50. }
  51. void AddEdge(int x,int y,int z){
  52. e[len].to=y;
  53. e[len].cap=z;
  54. e[len].prev=last[x];
  55. last[x]=len++;
  56. }
  57. int Dinic(){
  58. int ans=;
  59. for(;;){
  60. bfs(s);
  61. if(d[t]>n)break;
  62. memset(now,,sizeof(now));
  63. ans+=dfs(s,~(<<));
  64. }
  65. return ans;
  66. }
  67. void bfs(int x){
  68. memset(d,,sizeof(d));
  69. d[x]=;
  70. head=tail=;
  71. q[tail++]=x;
  72. while(head!=tail){
  73. x=q[head++];
  74. for(int i=last[x];i!=-;i=e[i].prev)if(e[i].cap>&&d[e[i].to]>n){
  75. d[e[i].to]=d[x]+;
  76. q[tail++]=e[i].to;
  77. }
  78. }
  79. }
  80. int dfs(int x,int delta){
  81. if(x==t||!delta)return delta;
  82. int flow=,f;
  83. for(int i=now[x]?e[now[x]].prev:last[x];i!=-;i=e[i].prev)if(e[i].cap>&&d[e[i].to]==d[x]+){
  84. now[x]=i;
  85. f=dfs(e[i].to,min(delta,e[i].cap));
  86. if(!f)continue;
  87. e[i].cap-=f;
  88. e[i^].cap+=f;
  89. flow+=f;
  90. delta-=f;
  91. if(!delta)break;
  92. }
  93. return flow;
  94. }

网络流n题 题解的更多相关文章

  1. 【题解】【网络流24题】航空路线问题 [P2770] [Loj6122]

    [题解][网络流24题]航空路线问题 [P2770] [Loj6122] 传送门:航空路线问题 \([P2770]\) \([Loj6122]\) [题目描述] 给出一张有向图,每个点(除了起点 \( ...

  2. 【题解】【网络流24题】汽车加油行驶问题 [P4009] [Loj6223]

    [题解][网络流24题]汽车加油行驶问题 [P4009] [Loj6223] 传送门:汽车加油行驶问题 \([P4009]\) \([Loj6223]\) [题目描述] 给出一个 \(N \times ...

  3. [网络流24题]最长k可重区间集[题解]

    最长 \(k\) 可重区间集 题目大意 给定实心直线 \(L\) 上 \(n\) 个开区间组成的集合 \(I\) ,和一个正整数 \(k\) ,试设计一个算法,从开区间集合 \(I\) 中选取开区间集 ...

  4. 【线性规划与网络流 24题】已完成(3道题因为某些奇怪的原因被抛弃了QAQ)

    写在前面:SDOI2016 Round1滚粗后蒟蒻开始做网络流来自我拯救(2016-04-11再过几天就要考先修课,现在做网络流24题貌似没什么用←退役节奏) 做的题目将附上日期,见证我龟速刷题. 1 ...

  5. LOJ6000 - 「网络流 24 题」搭配飞行员

    原题链接 题意简述 求二分图的最大匹配. 题解 这里写的是匈牙利算法. 表示节点的当前匹配. 为真表示在这一轮匹配中,无法给节点一个新的匹配.所以如果为真就不用再dfs它了,直接continue就好. ...

  6. 【网络流24题】最长k可重线段集(费用流)

    [网络流24题]最长k可重线段集(费用流) 题面 Cogs的数据有问题 Loj 洛谷 题解 这道题和最长k可重区间集没有区别 只不过费用额外计算一下 但是,还是有一点要注意的地方 这里可以是一条垂直的 ...

  7. 【网络流24题】最长k可重区间集(费用流)

    [网络流24题]最长k可重区间集(费用流) 题面 Cogs Loj 洛谷 题解 首先注意一下 这道题目里面 在Cogs上直接做就行了 洛谷和Loj上需要判断数据合法,如果\(l>r\)就要交换\ ...

  8. 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题

    题目描述 给定平面 \(\text{xoy}\) 上 \(n\) 个开线段组成的集合 \(\text{I}\) ,和一个正整数 \(k\) ,试设计一个算法. 从开线段集合 \(\text{I}\) ...

  9. 【刷题】LOJ 6121 「网络流 24 题」孤岛营救问题

    题目描述 1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形 ...

随机推荐

  1. XCodeo如何去除多余的模拟器---学习笔记七

    首先退出Xcode并且关闭模拟器: 然后在终端(Terminal)输入如下2行命令: sudo killall -9 com.apple.CoreSimulator.CoreSimulatorServ ...

  2. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  3. Learning Roadmap of Robotic Operating System (ROS)

    ROS Wiki: http://wiki.ros.org/ Robots Using ROS Textbooks: A Gentle Introduction to ROS Learning ROS ...

  4. 手机网页Html代码实现(解决显示页面很小的问题)

    工作需要,要做一个手机自适应的网页效果,终于搞定,先分享并记录! 其实主要就是改掉HTML页面声明: 在网页中加入以下代码,就可以正常显示了: <meta name="viewport ...

  5. 如何设置ASP.NET页面的运行超时时间

    全局超时时间 服务器上如果有多个网站,希望统一设置一下超时时间,则需要设置 Machine.config 文件中的 ExecutionTimeout 属性值.Machine.config 文件位于 % ...

  6. Ionic中使用Chart.js进行图表展示以及在iOS/Android中的性能差异

    Angular Chart 简介 在之前的文章中介绍了使用 Ionic 开发跨平台(iOS & Android)应用中遇到的一些问题的解决方案. 在更新0.1.3版本的过程中遇到了需要使用图表 ...

  7. CCS 6新建TMS320F2812工程

    准备材料 CCS6 下载地址:http://www.ti.com/tool/ccstudio F2812的C语言头文件 下载地址:http://www.ti.com/lit/zip/sprc097 安 ...

  8. Android ORM 框架之 greenDAO 使用心得

    前言 我相信,在平时的开发过程中,大家一定会或多或少地接触到 SQLite.然而在使用它时,我们往往需要做许多额外的工作,像编写 SQL 语句与解析查询结果等.所以,适用于 Android 的ORM  ...

  9. HTML form 表单

    1.id.name的关系 通常我们在写HTML代码时,会给控件指定一个id属性,这个属性只供JS和CSS使用,在表单提交时,它不起任何作用; 在HTML代码中我们会指定不同的value为各个不同的控件 ...

  10. VS 团队资源管理 强制解锁锁定文件

    故事是这样发生的: 以前有台电脑,在团队资源里看程序,可能冥冥中不小心按了个空格,so,文件被锁定 而我却没有发现 如果再给我一个机会,我只想说记得签入 然后,高潮来了 重装电脑 欣喜的装好新机子打开 ...