利用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费用流以后再介绍

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9450474.html