[ZJOI2010]网络扩容
题目链接:https://www.luogu.org/problemnew/show/P2604
完全能当最大流和费用流两个板子的题。
题意简述:n个点,m条边,每条边除了给出连接的两个点与流量之外,额外给出将流量增加1的费用。
求1-n的最大流,以及将最大流增加k的最小费用。
最大流好办,忽视增加流量这种事,直接上板子即可。
增加k的最小费用,显然将所有边的流量增加k是不行的。额外增加一个汇点,由n向汇点连一条流量为ans+k(ans为原图答案),费用为0的边,这样就可以保证最大流就是ans+k
其他的边要分两次来建,分别是流量不变,费用为0的边,和流量inf(>=k即可),费用为增流费用的边,之后就是费用流板子了。
#include<cstdio> #include<queue> #include<cstring> #include<algorithm> using namespace std; const int inf=(1<<30); void read(int &y) { y=0;char x=getchar(); int f=1; while(x<'0'||x>'9') { if(x=='-') f=-1; x=getchar(); } while(x>='0'&&x<='9') { y=y*10+x-'0'; x=getchar(); } y*=f; } struct edge { int u,v,w,c; int frm; }e[20005]; int n,m,k,cnt=1; int s,t,ans; int head[1005],fr[1005]; int a[5005],b[5005],d[5005],g[5005]; int dis[1005],vis[1005]; void add1(int u,int v,int w) { e[++cnt].u=head[u];head[u]=cnt; e[cnt].v=v;e[cnt].w=w; e[++cnt].u=head[v];head[v]=cnt; e[cnt].v=u;e[cnt].w=0; } void add(int u,int v,int w,int c) { e[++cnt].u=head[u];e[cnt].v=v; e[cnt].w=w;e[cnt].c=c; e[cnt].frm=u;head[u]=cnt; e[++cnt].u=head[v];e[cnt].v=u; e[cnt].w=0;e[cnt].c=-c; e[cnt].frm=v;head[v]=cnt; } int bfs() { memset(dis,0,sizeof(dis)); queue<int>q; q.push(1);dis[1]=1; while(!q.empty()) { int tmp=q.front();q.pop(); for(int i=head[tmp];i!=-1;i=e[i].u) { int p=e[i].v; if(dis[p]||e[i].w<=0) continue; dis[p]=dis[tmp]+1; q.push(p); } } return dis[t]; } int dfs(int x,int f) { if(x==t) return f; int d,tmp=0; for(int i=head[x];i!=-1;i=e[i].u) { int nxt=e[i].v; if(dis[nxt]==dis[x]+1&&e[i].w>0) { d=dfs(nxt,min(f-tmp,e[i].w)); if(d==0) continue; e[i].w-=d; e[i^1].w+=d; tmp+=d; if(tmp==f) return tmp; } } if(!tmp) dis[x]=0; return tmp; } int spfa() { for(int i=1;i<=t;i++) dis[i]=inf; memset(vis,0,sizeof(vis)); queue<int>q; q.push(1); vis[1]=1;dis[1]=0; while(!q.empty()) { int nxt=q.front();q.pop(); for(int i=head[nxt];i!=-1;i=e[i].u) { int tmp=e[i].v; if(dis[tmp]>dis[nxt]+e[i].c&&e[i].w) { dis[tmp]=dis[nxt]+e[i].c; fr[tmp]=i; if(vis[tmp]==0) { vis[tmp]=1; q.push(tmp); } } } vis[nxt]=0; } if(dis[t]==inf) return 0; return 1; } int mcf() { int re=0,x=inf; for(int i=fr[t];i;i=fr[e[i].frm]) x=min(e[i].w,x); for(int i=fr[t];i;i=fr[e[i].frm]) { e[i].w-=x; e[i^1].w+=x; re+=x*e[i].c; } return re; } int main() { read(n);read(m);read(k); memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++) { read(a[i]);read(b[i]);read(d[i]);read(g[i]); add1(a[i],b[i],d[i]); } t=n; while(bfs()) ans+=dfs(1,inf); printf("%d ",ans); memset(head,-1,sizeof(head)); cnt=1; for(int i=1;i<=m;i++) { add(a[i],b[i],d[i],0); add(a[i],b[i],inf,g[i]); } t=n+1; add(n,t,ans+k,0); ans=0; while(spfa()) ans+=mcf(); printf("%d",ans); return 0; }