Description
Given a directed graph, each edge has a capacity C and an expansion cost W. Here, the expansion cost refers to the cost of expanding capacity by 1.
Ask:
1. The maximum flow from 1 to N without capacity expansion;
2. The minimum expansion cost required to increase the maximum flow from 1 to N by K.
Input
The first row contains three integers, N,M,K, representing the number of points, edges, and the amount of traffic that needs to be increased.
The next M lines contain four integers u,v,C,W, representing an edge from u to v with capacity of C and expansion cost of W.
N<=1000,M<=5000,K<=10
Output
The output file line contains two integers representing the answers to question 1 and question 2, respectively.
Sample Input
5 8 2 1 2 5 8 2 5 9 9 5 1 6 2 5 1 1 8 1 2 8 7 2 5 4 9 1 2 1 1 1 4 2 1
Sample Output
13 19
Solution
The first question can be solved directly with the maximum flow
Second, because k is not more than 10, you can run the cost flow k times and add 1 flow to each side with 0 flow. If it is the first time, add the cost. If it is the second time, add the negative cost to the opposite side.
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define N 1010
#define M 5050
#define INF 0x7ffffff
struct edge
{
int x,d,y,w,c,next;
};
edge side[M*2];
int last[N],dis[N],t[N],pre[N];
int n,m,k,l=1,s,e;
void add(int x,int y,int w,int c)
{
l++;
side[l].x=x;
side[l].y=y;
side[l].w=w;
side[l].c=c;
side[l].d=0;
side[l].next=last[x];
last[x]=l;
}
void init()
{
scanf("%d%d%d",&n,&m,&k);
int x,y,c,w;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&x,&y,&w,&c);
add(x,y,w,c);
add(y,x,0,-c);
}
}
queue<int> Q;
bool bfs()
{
memset(dis,0,sizeof(dis));
dis[1]=1;
Q.push(1);
while (!Q.empty())
{
int now=Q.front(); Q.pop();
for (int i=last[now];i!=0;i=side[i].next)
{
int j=side[i].y;
if (side[i].w==0 || dis[j]!=0) continue;
dis[j]=dis[now]+1;
Q.push(j);
}
}
if (dis[n]==0) return false;
else return true;
}
int dfs(int x,int maxf)
{
if (x==n || maxf==0) return maxf;
int ret=0;
for (int i=last[x];i!=0;i=side[i].next)
{
int j=side[i].y;
if (side[i].w==0 || dis[x]+1!=dis[j]) continue;
int f=dfs(j,min(maxf-ret,side[i].w));
side[i].w-=f;
side[i^1].w+=f;
ret+=f;
if (ret==maxf) break;
}
return ret;
}
void dinic()
{
int ans=0;
while (bfs()) ans+=dfs(1,INF);
printf("%d ",ans);
}
void spfa()
{
for (int i=1;i<=n;i++)
dis[i]=INF;
memset(t,0,sizeof(t));
memset(pre,0,sizeof(pre));
Q.push(1);
dis[1]=0; t[1]=1;
while (!Q.empty())
{
int now=Q.front(); Q.pop();
for (int i=last[now];i!=0;i=side[i].next)
{
if (side[i].w<=0) continue;
int j=side[i].y;
if (dis[j]>dis[now]+side[i].d)
{
dis[j]=dis[now]+side[i].d;
pre[j]=i;
if (t[j]==0)
{
Q.push(j);
t[j]=1;
}
}
}
if (now!=1) t[now]=0;
}
//printf("%d\n",dis[n]);
}
int find()
{
spfa();
int s=0;
for (int i=pre[n];;i=pre[side[i].x])
{
side[i].w-=1;
side[i^1].w+=1;
if (side[i].w==0)
{
side[i].w=1;
if (side[i].d==side[i].c) side[i^1].d=side[i^1].c;
side[i].d=side[i].c;
}
if (side[i].x==1) break;
}
return dis[n];
}
int main()
{
init();
dinic();
for (int i=2;i<=l;i+=2)
if (side[i].w==0)
{
side[i].w=1;
side[i].d=side[i].c;
}
int ans=0;
for (int i=1;i<=k;i++)
ans+=find();
printf("%d\n",ans);
return 0;
}