uva1658 算法竞赛入门经典海军上将费用流
Posted lqllulu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uva1658 算法竞赛入门经典海军上将费用流相关的知识,希望对你有一定的参考价值。
题意
给出一个v(3<=v<=1000)个点e(3<=e<=10000)条边的有向加权图,求1-v的两条不相交(除了起点和终点外没有公共点)的路径,使得权和最小。
分析
费用流的一个经典用法就是限制没有公共边边,但是这个题有个不同,这个题限制的是没有公共点。因此,我们把每个点拆出一条边来。
把2到v-1的每个结点i拆成i和i‘两个结点,中间连一条容量为1,费用为0的边。对于原图中的每一条边(a,b),连一条弧(a‘,b),容量为1,费用为权值然后求1到v的流量为2的最小费用流即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 7 using namespace std; 8 const int maxn=4000+10; 9 const int maxm=40000+10; 10 const int INF=2147480000; 11 struct MCMF{ 12 int head[maxn],Next[maxm],to[maxm],from[maxm],flow[maxm],cap[maxm],cost[maxm]; 13 int inq[maxn],d[maxn],p[maxn],a[maxn]; 14 int n,m,s,t,sz; 15 void init(int n){ 16 this->n=n; 17 sz=-1; 18 memset(head,-1,sizeof(head)); 19 } 20 void add_edge(int a,int b,int ca,int co){ 21 ++sz; 22 from[sz]=a;to[sz]=b;Next[sz]=head[a];head[a]=sz; 23 cap[sz]=ca;cost[sz]=co;flow[sz]=0; 24 ++sz; 25 from[sz]=b;to[sz]=a;Next[sz]=head[b];head[b]=sz; 26 cap[sz]=ca;cost[sz]=-co;flow[sz]=ca; 27 } 28 bool spfa(int s,int t,int &Flow ,long long &Cost){ 29 for(int i=0;i<=n;i++)d[i]=INF; 30 queue<int>Q; 31 memset(inq,0,sizeof(inq)); 32 d[s]=0;inq[s]=1;p[s]=-1;a[s]=INF; 33 Q.push(s); 34 while(!Q.empty()){ 35 int u=Q.front();Q.pop(); 36 inq[u]=0; 37 for(int i=head[u];i!=-1;i=Next[i]){ 38 int v=to[i]; 39 if(cap[i]>flow[i]&&d[v]>d[u]+cost[i]){ 40 d[v]=d[u]+cost[i]; 41 p[v]=i; 42 a[v]=min(a[u],cap[i]-flow[i]); 43 if(!inq[v]){ 44 inq[v]=1; 45 Q.push(v); 46 } 47 } 48 } 49 } 50 if(d[t]==INF)return false; 51 Flow+=a[t]; 52 Cost+=(long long)a[t]*(long long)d[t]; 53 int u=t; 54 while(u!=s){ 55 flow[p[u]]+=a[t]; 56 flow[p[u]^1]-=a[t]; 57 u=from[p[u]]; 58 } 59 return true; 60 } 61 long long Mincost(int s,int t){ 62 int Flow=0; 63 long long Cost=0; 64 while(spfa(s,t,Flow,Cost)); 65 return Cost; 66 } 67 }mcmf; 68 int n,m; 69 int main(){ 70 while(scanf("%d%d",&n,&m)!=EOF){ 71 int a,b,c; 72 mcmf.init(2*n); 73 for(int i=2;i<n;i++){ 74 mcmf.add_edge(i,i+n,1,0); 75 } 76 mcmf.add_edge(1,n+1,2,0); 77 mcmf.add_edge(n,2*n,2,0); 78 for(int i=1;i<=m;i++){ 79 scanf("%d%d%d",&a,&b,&c); 80 mcmf.add_edge(a+n,b,1,c); 81 } 82 int ans=mcmf.Mincost(1,2*n); 83 cout<<ans<<endl; 84 } 85 return 0; 86 }
以上是关于uva1658 算法竞赛入门经典海军上将费用流的主要内容,如果未能解决你的问题,请参考以下文章
UVA1658 Admiral 拆点法解决结点容量(路径不能有公共点,容量为1的时候) 最小费用最大流