1834: [ZJOI2010]network 网络扩容
Time Limit: 3 Sec Memory Limit: 64 MB
Submit: 2334 Solved: 1174
Description
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
Input
输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
Output
输出文件一行包含两个整数,分别表示问题1和问题2的答案。
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
HINT
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10
Source
Day1
最大流+最小费用最大流。。
其实是一个模板题,我却因为一个SB的连边卡了好久。。
第一次打zkw费用流。。
第一问直接建图跑最大流即可。。
第二问在第一问上的残留网络上连边,对每条边连一个容量为+∞,费用为0的边,建一个超级源点,源点和1连一条容量为k,费用为0的边,然后跑zkw费用流即可。。
让DaD3zZ神犇和Claris学长看了好久没有看出端倪。。果然是我太弱。。
附上本蒟蒻的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
struct node
{
int to,next,v,c,from,t;
};
node edge[1000001];
int h[1000001],q[1000001],dis[1000001],head,tail,cnt=1,n,m,k,tmp=0,ans=0,sum=0,num;
bool mark[1000001],vis[1000001];
int read()
{
int w=0;
char ch=getchar();
while (ch>='0' && ch<='9')
{
w=w*10+ch-'0';
ch=getchar();
}
return w;
}
void add1(int u,int v,int w,int cost)
{
cnt++;
edge[cnt].next=h[u];
edge[cnt].from=u;
h[u]=cnt;
edge[cnt].to=v;
edge[cnt].v=w;
edge[cnt].t=cost;
}
void add2(int u,int v,int w,int cost)
{
cnt++;
edge[cnt].next=h[u];
edge[cnt].from=u;
edge[cnt].to=v;
h[u]=cnt;
edge[cnt].v=w;
edge[cnt].c=cost;
}
bool bfs()
{
int j,p;
memset(dis,-1,sizeof(dis));
q[1]=1;
dis[1]=0;
head=0;
tail=1;
while (head<tail)
{
head++;
j=q[head];
p=h[j];
while (p)
{
if (dis[edge[p].to]<0 && edge[p].v>0)
{
dis[edge[p].to]=dis[j]+1;
tail++;
q[tail]=edge[p].to;
}
p=edge[p].next;
}
}
if (dis[n]>0)
return true;
else
return false;
}
int dfs1(int x,int f)
{
int w,used=0,i=h[x];
if (x==n)
return f;
while (i)
{
if (edge[i].v && dis[edge[i].to]==dis[x]+1)
{
w=f-used;
w=dfs1(edge[i].to,min(w,edge[i].v));
edge[i].v-=w;
edge[i^1].v+=w;
used+=w;
if (used==f)
return f;
}
i=edge[i].next;
}
if (!used)
dis[x]=-1;
return used;
}
bool spfa()
{
int i,now;
memset(vis,false,sizeof(vis));
for (i=0;i<=n;i++)
dis[i]=0x7fffffff;
head=0;
tail=1;
q[0]=n;
vis[n]=true;
dis[n]=0;
while (head<tail)
{
now=q[head];
head++;
vis[now]=false;
for (i=h[now];i;i=edge[i].next)
if (edge[i^1].v && dis[now]-edge[i].c<dis[edge[i].to])
{
dis[edge[i].to]=dis[now]-edge[i].c;
if (!vis[edge[i].to])
{
vis[edge[i].to]=true;
q[tail]=edge[i].to;
tail++;
}
}
}
return dis[0]!=0x7fffffff;
}
int dfs2(int x,int f)
{
int w,used=0,i;
mark[x]=true;
if (x==n)
return f;
for (i=h[x];i;i=edge[i].next)
if (dis[edge[i].to]==dis[x]-edge[i].c && edge[i].v && !mark[edge[i].to])
{
w=f-used;
w=dfs2(edge[i].to,min(w,edge[i].v));
sum+=w*edge[i].c;
edge[i].v-=w;
edge[i^1].v+=w;
used+=w;
if (used==f)
return f;
}
return used;
}
int main()
{
int i,u,v,flow,cost;
n=read();
m=read();
k=read();
for (i=1;i<=m;i++)
{
u=read();
v=read();
flow=read();
cost=read();
add1(u,v,flow,cost);
add1(v,u,0,-cost);
}
while (bfs())
while (sum=dfs1(1,0x7fffffff))
ans+=sum;
num=cnt;
for (i=2;i<=num;i+=2)
{
add2(edge[i].from,edge[i].to,0x7fffffff,edge[i].t);
add2(edge[i].to,edge[i].from,0,-edge[i].t);
}
add1(0,1,k,0);
add1(1,0,0,0);
sum=0;
while (spfa())
{
mark[n]=true;
while (mark[n])
{
memset(mark,false,sizeof(mark));
tmp+=dfs2(0,0x7fffffff);
}
}
printf("%d %d",ans,sum);
return 0;
}