[ZJOI2010]网络扩容——最小费用最大流

题目描述

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

输入

第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 
接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
N<=1000,M<=5000,K<=10

输出

输出文件一行包含两个整数,分别表示问题1和问题2的答案。

第一问没啥可说的,直接最大流就行。第二问显然是求最小费用最大流,第二次加边直接残量网络上把对应边建出来,不用再重新建图,只要把第一次建的边边权赋成INF,就能保证一定走的是第二次加的边。第二次加的边因为不确定每条边容量,所以都设成INF,但又要限制总流量,所以新建一个源点连一条边到原来的源点,容量为k,这样就保证了全图流量。

最后附上代码。

  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<iostream>
  6 #include<algorithm>
  7 using namespace std;
  8 queue<int>Q;
  9 int A[5010];
 10 int B[5010];
 11 int C[5010];
 12 int D[5010];
 13 int f[5010];
 14 int vis[5010];
 15 int c[100001];
 16 int d[100001];
 17 int q[100001];
 18 int to[100001];
 19 int val[100001];
 20 int next[100001];
 21 int from[100001];
 22 int head[100001];
 23 int S,T;
 24 int sum;
 25 int ans=0;
 26 int tot=1;
 27 int n,m,k;
 28 int max_flow=0;
 29 int INF=2147483647;
 30 void add(int x,int y,int z,int w)
 31 {
 32     tot++;
 33     next[tot]=head[x];
 34     head[x]=tot;
 35     to[tot]=y;
 36     c[tot]=z;
 37     val[tot]=w;
 38     from[tot]=x;
 39     tot++;
 40     next[tot]=head[y];
 41     head[y]=tot;
 42     to[tot]=x;
 43     c[tot]=0;
 44     val[tot]=-w;
 45     from[tot]=y;
 46 }
 47 int dfs(int x,int maxflow)
 48 {
 49     if(x==T)
 50     {
 51         return maxflow;
 52     }
 53     int used=0;
 54     int nowflow;
 55     for(int i=head[x];i;i=next[i])
 56     {
 57         if(c[i]!=0&&d[to[i]]==d[x]+1)
 58         {
 59             nowflow=dfs(to[i],min(maxflow-used,c[i]));
 60             c[i]-=nowflow;
 61             c[i^1]+=nowflow;
 62             used+=nowflow;
 63             if(nowflow==maxflow)
 64             {
 65                 return maxflow;
 66             }
 67         }
 68     }
 69     if(used==0)
 70     {
 71         d[x]=-1;
 72     }
 73     return used;
 74 }
 75 bool bfs(int S,int T)
 76 {
 77     memset(d,-1,sizeof(d));
 78     memset(q,0,sizeof(q));
 79     d[S]=0;
 80     int l=0;
 81     int r=0;
 82     q[r++]=S;
 83     while(l<r)
 84     {
 85         int now=q[l];
 86         for(int i=head[now];i;i=next[i])
 87         {
 88             if(d[to[i]]==-1&&c[i]!=0)
 89             {
 90                 d[to[i]]=d[now]+1;
 91                 q[r++]=to[i];
 92             }
 93         }
 94         l++;
 95     }
 96     if(d[T]!=-1)
 97     {
 98         return true;
 99     }
100     return false;
101 }
102 void dinic()
103 {
104     while(bfs(S,T)==true)
105     {
106         ans+=dfs(S,INF);
107     }
108 }
109 bool SPFA()
110 {
111     for(int i=0;i<=T;i++)
112     {
113         d[i]=INF;
114     }
115     d[S]=0;
116     Q.push(S);
117     vis[S]=1;
118     while(!Q.empty())
119     {
120         int now=Q.front();
121         Q.pop();
122         vis[now]=0;
123         for(int i=head[now];i;i=next[i])
124         {
125             if(!c[i])
126             {
127                 continue;
128             }
129             if(d[to[i]]>d[now]+val[i])
130             {
131                 d[to[i]]=d[now]+val[i];
132                 f[to[i]]=i;
133                 if(!vis[to[i]])
134                 {
135                     Q.push(to[i]);
136                     vis[to[i]]=1;
137                 }
138             }
139         }
140     }
141     return d[T]!=INF;
142 }
143 void result()
144 {
145     int now=T;
146     int flow=INF;
147     while(now!=S)
148     {
149         flow=min(flow,c[f[now]]);
150         now=from[f[now]];
151     }
152     max_flow+=flow;
153     sum+=d[T]*flow;
154     now=T;
155     while(now!=S)
156     {
157         c[f[now]]-=flow;
158         c[f[now]^1]+=flow;
159         now=from[f[now]];
160     }
161 }
162 void find_min()
163 {
164     while(SPFA())
165     {
166         result();
167     }
168 }
169 int main()
170 {
171     scanf("%d%d%d",&n,&m,&k);
172     S=1;
173     T=n;
174     for(int i=1;i<=m;i++)
175     {
176         scanf("%d%d%d%d",&A[i],&B[i],&C[i],&D[i]);
177         add(A[i],B[i],C[i],0);
178     }
179     dinic();
180     printf("%d ",ans);
181     for(int i=1;i<=m;i++)
182     {
183         add(A[i],B[i],INF,D[i]);
184     }
185     S=0;
186     add(S,1,k,0);
187     find_min();
188     printf("%d",sum);
189 }

猜你喜欢

转载自www.cnblogs.com/Khada-Jhin/p/9123408.html
今日推荐