利用SPFA+EK算法解决费用流问题
例题不够裸,但是还是很有说服力的,这里以Codevs1227的方格取数2为例子来介绍费用流问题
这个题难点在建图上,我感觉以后还要把网络流建模想明白才能下手去做这种题,老实说挺难的
先直接给出建图的代码:
scanf("%d",&x); //把每个节点拆成两个,分别为ai和bi //ai向bi连边,费用为权值,容量为1 //再连边,费用为0,容量为k,保证联通 addedge((i-1)*n+j,(i-1)*n+j+n*n,1,x); addedge((i-1)*n+j,(i-1)*n+j+n*n,k,0); //让bi能往下面或者左面走 if(j<n) addedge((i-1)*n+j+n*n,(i-1)*n+j+1,k,0); if(i<n) addedge((i-1)*n+j+n*n,i*n+j,k,0);
然后给出完整实现,请记住cnt初始必须是1,为了和^配套使用
否则RE???
差点儿把以后的自己坑死
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=6005; 6 const int maxm=1000005; 7 const int INF=0x7fffffff; 8 int n,k,cnt=1; 9 bool inq[maxn]; 10 int g[maxn],dis[maxn],q[maxm],from[maxn]; 11 long long ans; 12 struct Edge{int from,to,v,c,next;}e[maxm]; 13 void addedge(int u,int v,int w,int c) //cost是费用 14 { 15 e[++cnt].from=u;e[cnt].to=v;e[cnt].v=w;e[cnt].c=c; 16 e[cnt].next=g[u];g[u]=cnt; 17 18 e[++cnt].from=v;e[cnt].to=u;e[cnt].v=0;e[cnt].c=-c; 19 e[cnt].next=g[v];g[v]=cnt; 20 } 21 bool spfa() 22 { 23 int t=0,w=1,u; 24 memset(dis,-1,sizeof(dis)); 25 q[0]=0;dis[0]=0;inq[0]=1; 26 while(t<w) 27 { 28 u=q[t];t++; 29 for(int tmp=g[u];tmp;tmp=e[tmp].next) 30 { 31 if(e[tmp].v>0&&dis[u]+e[tmp].c>dis[e[tmp].to]) 32 { 33 dis[e[tmp].to]=dis[u]+e[tmp].c; 34 from[e[tmp].to]=tmp; 35 if(!inq[e[tmp].to]) 36 {q[w]=e[tmp].to;w++;inq[e[tmp].to]=1;} 37 } 38 } 39 inq[u]=0; 40 } 41 if(dis[6000]==-1) return 0; 42 return 1; 43 } 44 void mincf() 45 { 46 int sum=INF; 47 int tmp=from[6000]; 48 while(tmp) 49 { 50 sum=min(sum,e[tmp].v); 51 tmp=from[e[tmp].from]; 52 } 53 tmp=from[6000]; 54 while(tmp) 55 { 56 e[tmp].v-=sum; 57 e[tmp^1].v+=sum; 58 ans+=sum*e[tmp].c; 59 tmp=from[e[tmp].from]; 60 } 61 } 62 int main() 63 { 64 int x; 65 scanf("%d%d",&n,&k); 66 for(int i=1;i<=n;i++) 67 for(int j=1;j<=n;j++) 68 { 69 scanf("%d",&x); 70 //把每个节点拆成两个,分别为ai和bi 71 //ai向bi连边,费用为权值,容量为1 72 //再连边,费用为0,容量为k,保证联通 73 addedge((i-1)*n+j,(i-1)*n+j+n*n,1,x); 74 addedge((i-1)*n+j,(i-1)*n+j+n*n,k,0); 75 //让bi能往下面或者左面走 76 if(j<n) 77 addedge((i-1)*n+j+n*n,(i-1)*n+j+1,k,0); 78 if(i<n) 79 addedge((i-1)*n+j+n*n,i*n+j,k,0); 80 } 81 //源点和汇点 82 addedge(0,1,k,0); 83 addedge(n*n*2,6000,k,0); 84 while(spfa()) mincf(); 85 printf("%lld",ans); 86 return 0; 87 }
还有一点就是这个题是最大费用最大流,最小费用最大流还有ZKW费用流以后再介绍