P2598【ZJOI2010 Day1】网络扩容
时间限制 : 10000 MS 空间限制 : 65536 KB
问题描述
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求:
1.在不扩容的情况下,1到N的最大流;
2.将1到N的最大流增加K所需的最小扩容费用。
输入格式
第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。
接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
输出格式
包含两个整数,分别表示问题1和问题2的答案。
样例输入
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
样例输出
13 19
提示
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
题解:
先正常的跑一次最大流,然后在起点加一条容量为k的边,再在每一条边加一条容量无穷大且费用为w的边。再跑一次费用流即为答案。
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#include<queue>
#define maxn 22005
#define maxn1 1010 //反向边残量为0 长度为相反数
#define inf 99999999 //在spfa中不仅要记点还要记录边
using namespace std; //边存的费用流!!!注意细节
int Next[maxn],Last[maxn],St[maxn],End[maxn],Len[maxn],C[maxn];
int n,m,k;
int start;
int fei[maxn];
int dis[maxn1],path[maxn1],mark[maxn1],p2[maxn1];
int cnt=1;
int maxflow,mincost;
void add(int x,int y,int z,int w)
{
cnt++;
Next[cnt]=Last[x];
End[cnt]=y;
Last[x]=cnt;
C[cnt]=w;
Len[cnt]=z;
St[cnt]=x;
}
bool spfa()
{
int i,x,y;
queue<int>q;
for(i=start;i<=n;i++) dis[i]=inf;
memset(mark,false,sizeof(mark));
q.push(start);
mark[start]=true;//注意标记
dis[start]=0;
while(q.size())
{
int x=q.front();
q.pop();
mark[x]=false;
for(i=Last[x];i;i=Next[i])
{
int en=End[i];
if(C[i]>0&&dis[en]>dis[x]+Len[i])
{
dis[en]=dis[x]+Len[i];
path[en]=x;
p2[en]=i;
if(mark[en]==0){
q.push(en);
mark[en]=true;
}
}
}
}
if(dis[n]<inf) return true;
return false;
}
void addflow()
{
int s=n,flow=inf,cost=0,p=0;
for(;s!=start;s=path[s])
{
p=p2[s];
flow=min(flow,C[p]);
}
mincost+=flow*dis[n];
maxflow+=flow;
for(s=n;s!=start;s=path[s])
{
p=p2[s];
C[p]-=flow;
C[p^1]+=flow;
}
}
int main()
{
int i,j,k;
start=1;
scanf("%d%d%d",&n,&m,&k);
int x,y,w,z;
for(i=1;i<=m;i++)
{
scanf("%d%d%d%d",&x,&y,&w,&z);
add(x,y,0,w);
fei[cnt]=z;
add(y,x,0,0);
}
while(spfa()) addflow();
cout<<maxflow<<endl;
mincost=0;
int cntt=cnt;
for(i=2;i<=cntt;i+=2){
add(St[i],End[i],fei[i],inf);
add(End[i],St[i],-fei[i],0);
}
start=0;
add(start,1,0,k);
add(1,start,0,0);
while(spfa())addflow();
cout<<mincost<<endl;
}