由于一些采矿站不能直接相互通信,为了船舶导航的安全,船只只允许在可以直接相互通信的采矿站之间航行。
采矿是艰巨的,人们做这项工作需要适当的休息(也就是说,让船只返回港口)。但真是巧合!这次,n艘采矿船只轮流在同一时间休息。它们分散在不同的站点,现在它们必须返回港口,此外,一个港口只能容纳一艘船。现在所有船只将开始返回,如何选择他们的航行路线,使他们的航行路线的总和最小。
请注意,一旦船舶进入港口,它就不会出来!
思想:
采用贪心的思想。 通过SPFA,增广路的思想,每次找到一条从源点到达汇点的花费最小的路径
1 if(e.flow>0&&dis[e.v]>dis[now]+e.cost) 2 { 3 dis[e.v]=dis[now]+e.cost; //维护最小费用 4 addflow[e.v]=min(addflow[now],e.flow);//维护流量 5 pre[e.v]=i;//将点指向上一条边,方便回溯 6 7 if(!vis[e.v]) 8 { 9 q.push(e.v); 10 vis[e.v]=1; 11 } 12 }
增加流量,直到无法找到一条从源点到达汇点的路径,算法结束。 每次找一条花费最小的路径,从源点跑到汇点,然后维护这条路上所加的流量最小值(addflow函数),然后总流量加上流量。最后再回溯,将正向边减去,反向边加上流量。找到一条路径。再while循环这个过程,直到找不到S到T的点;这样每次找的边都保证费用最小,每次增加流量,直到没有路径增加,得到最小费用最大流;
回溯算法如下:
1 while(now!=s) 2 { 3 edg[pre[now]].flow-=addflow[t]; 4 edg[pre[now]^1].flow+=addflow[t]; 5 now=edg[pre[now]].u; 6 }
由于最大流量有限,每执行一次循环流量都会增加,因此该算法肯定会结束,且同时流量也必定会达到网络的最大流量;同时由于每次都是增加的最小的花费,即当前的最小花费是所有到达当前流量flow时的花费最小值,因此最后的总花费最小。
板子如下:
原题为:
3 5 5 6
1 2 4
1 3 3
1 4 4
1 5 5
2 5 3
2 4 3
1 1 5
1 5 3
2 5 3
2 4 6
3 1 4
3 2 2
13
1 #include<bits/stdc++.h> 2 #define INF INT_MAX/2 3 #define N 310 4 using namespace std; 5 6 typedef struct 7 { 8 int u,v,next; 9 int flow,cost; 10 }ss; 11 12 ss edg[N*N*4]; 13 int head[N]; 14 int now_edge=0; 15 16 void init() 17 { 18 memset(head,-1,sizeof(head)); 19 now_edge=0; 20 } 21 22 void inline addedge(int u,int v,int flow,int cost) 23 { 24 edg[now_edge]=(ss){u,v,head[u],flow,cost}; 25 head[u]=now_edge++; 26 edg[now_edge]=(ss){v,u,head[v],0,-cost}; 27 head[v]=now_edge++; 28 } 29 30 31 int dis[N]; 32 int vis[N]={0}; 33 int addflow[N]={0}; 34 int pre[N]={0}; 35 queue<int>q; 36 37 bool spfa(int s,int t,int &flow,int &cost) 38 { 39 for(int i=0;i<N;i++) 40 { 41 dis[i]=INF; 42 vis[i]=0; 43 } 44 45 while(!q.empty())q.pop(); 46 dis[s]=0; 47 vis[s]=1; 48 q.push(s); 49 addflow[s]=INF; 50 while(!q.empty()) 51 { 52 int now=q.front(); 53 q.pop(); 54 vis[now]=0; 55 56 for(int i=head[now];i!=-1;i=edg[i].next) 57 { 58 ss e=edg[i]; 59 60 if(e.flow>0&&dis[e.v]>dis[now]+e.cost) 61 { 62 dis[e.v]=dis[now]+e.cost; 63 addflow[e.v]=min(addflow[now],e.flow); 64 pre[e.v]=i; 65 66 if(!vis[e.v]) 67 { 68 q.push(e.v); 69 vis[e.v]=1; 70 } 71 } 72 } 73 } 74 75 if(dis[t]==INF)return false; 76 77 flow+=addflow[t]; 78 cost+=addflow[t]*dis[t]; 79 80 int now=t; 81 while(now!=s) 82 { 83 edg[pre[now]].flow-=addflow[t]; 84 edg[pre[now]^1].flow+=addflow[t]; 85 now=edg[pre[now]].u; 86 } 87 88 return true; 89 } 90 91 void MCMF(int s,int t,int &flow,int &cost) 92 { 93 while(spfa(s,t,flow,cost)); 94 } 95 96 97 98 int main() 99 { 100 int n,m,p,k; 101 while(scanf("%d %d %d %d",&n,&m,&k,&p)==4) 102 { 103 init(); 104 int s=n+m+1; 105 int t=s+1; 106 107 for(int i=1;i<=n;i++) 108 { 109 int a; 110 scanf("%d",&a); 111 addedge(s,a+n,1,0); 112 } 113 114 while(k--) 115 { 116 int u,v,w; 117 scanf("%d %d %d",&u,&v,&w); 118 addedge(n+u,n+v,INF,w); 119 addedge(n+v,n+u,INF,w); 120 } 121 122 while(p--) 123 { 124 int u,v,w; 125 scanf("%d %d %d",&u,&v,&w); 126 addedge(n+v,u,INF,w); 127 } 128 129 for(int i=1;i<=n;i++)addedge(i,t,1,0); 130 int flow=0,cost=0; 131 MCMF(s,t,flow,cost); 132 printf("%d\n",cost); 133 } 134 135 return 0; 136 }
原文:https://www.cnblogs.com/sylvia1111/p/11317481.html