测试地址:网络扩容
做法:本题需要用到最大流+费用流+拆边。
首先第一问直接做最大流就行了,记得到的答案为,主要是第二问。我们发现原网络中的边的费用可以用一个分段函数表示,即当流量超过原容量时,费用为超出部分乘上扩容费用,显然我们可以把这条边拆成一条容量为原容量,费用为的边和一条容量为正无穷,费用为扩容费用的边。这个网络有一个非常明显的问题,那就是它的最大流并不是我们要求的,这要怎么办呢?非常简单,只用从点连一条容量为,费用为的边到一个超级汇点上,这样从点到超级汇点的最大流就一定是了,这样我们就做一个最小费用最大流即可。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
const int inf=1000000000;
int n,m,S,T,k,u[5010],v[5010],w[5010];
int first[1010]={0},tot=1;
int lvl[1010],cur[1010];
int dis[1010],laste[1010],last[1010];
bool vis[1010];
queue<int> Q;
struct edge
{
int v,next,f,c;
}e[100010];
void insert(int a,int b,int f,int c)
{
e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,e[tot].c=c,first[a]=tot;
e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,e[tot].c=-c,first[b]=tot;
}
void init()
{
scanf("%d%d%d",&n,&m,&k);
S=1,T=n;
for(int i=1;i<=m;i++)
{
int c;
scanf("%d%d%d%d",&u[i],&v[i],&c,&w[i]);
insert(u[i],v[i],c,0);
}
}
bool makelevel()
{
for(int i=1;i<=T;i++)
lvl[i]=-1,cur[i]=first[i];
lvl[S]=0;
Q.push(S);
while(!Q.empty())
{
int v=Q.front();Q.pop();
for(int i=first[v];i;i=e[i].next)
if (e[i].f&&lvl[e[i].v]==-1)
{
lvl[e[i].v]=lvl[v]+1;
Q.push(e[i].v);
}
}
return lvl[T]!=-1;
}
int maxflow(int v,int maxf)
{
if (v==T) return maxf;
int ret=0,f;
for(int i=cur[v];i;i=e[i].next)
{
if (e[i].f&&lvl[e[i].v]==lvl[v]+1)
{
f=maxflow(e[i].v,min(maxf-ret,e[i].f));
ret+=f;
e[i].f-=f;
e[i^1].f+=f;
if (ret==maxf) break;
}
cur[v]=i;
}
if (!ret) lvl[v]=-1;
return ret;
}
void dinic()
{
int maxf=0;
while(makelevel())
maxf+=maxflow(S,inf);
printf("%d ",maxf);
}
void init2()
{
T=n+1;
insert(n,T,k,0);
for(int i=1;i<=m;i++)
insert(u[i],v[i],inf,w[i]);
}
bool spfa()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=T;i++)
dis[i]=inf;
dis[S]=0;
vis[S]=1;
Q.push(S);
while(!Q.empty())
{
int v=Q.front();Q.pop();
for(int i=first[v];i;i=e[i].next)
if (e[i].f&&dis[e[i].v]>dis[v]+e[i].c)
{
dis[e[i].v]=dis[v]+e[i].c;
laste[e[i].v]=i;
last[e[i].v]=v;
if (!vis[e[i].v]) vis[e[i].v]=1,Q.push(e[i].v);
}
vis[v]=0;
}
return dis[T]!=inf;
}
void mincost()
{
int minc=0;
while(spfa())
{
int x=T,maxf=inf;
while(x!=S)
{
maxf=min(maxf,e[laste[x]].f);
x=last[x];
}
x=T;
while(x!=S)
{
e[laste[x]].f-=maxf;
e[laste[x]^1].f+=maxf;
x=last[x];
}
minc+=maxf*dis[T];
}
printf("%d",minc);
}
int main()
{
init();
dinic();
init2();
mincost();
return 0;
}