[ZJOI2010]網路擴容,P2604,最小費用最大流
阿新 • • 發佈:2018-12-04
正題
這一題想了我很久,結果發現很智障。
原來是一個裸題啊。
先跑最大流,然後剩下的是一個殘餘網路,容易知道如果擴容,肯定在殘餘網路裡面找路徑,因為如果不在殘餘網路裡面找路徑,那麼肯定就會多算,就相當於有流量不用。
在殘餘網路裡面連邊,流量無限,費用是擴容費用。
建立一個超級源點,向1點建一條邊,流量為擴容大小,費用為0。跑一邊MCMF即可。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<queue> using namespace std; int n,m,k; struct edge{ int x,y,next,c,cos; }s[50010]; int first[1010],d[1010],mmin[1010],last[1010],w[5010]; bool tf[1010]; int begin,end; queue<int> f; int len=1; void ins(int x,int y,int c,int cos){ len++;s[len]=(edge){x,y,first[x],c,cos};first[x]=len; len++;s[len]=(edge){y,x,first[y],0,-cos};first[y]=len; } bool SPFA(int&flow,int&cost){ memset(tf,false,sizeof(tf));tf[begin]=true; memset(d,63,sizeof(d));d[begin]=0; mmin[begin]=1e9; f.push(begin); while(!f.empty()){ int x=f.front();f.pop();tf[x]=false; for(int i=first[x];i!=0;i=s[i].next){ int y=s[i].y; if(d[y]>d[x]+s[i].cos && s[i].c>0){ d[y]=d[x]+s[i].cos;mmin[y]=min(mmin[x],s[i].c);last[y]=i; if(!tf[y]){ tf[y]=true; f.push(y); } } } } if(d[end]==d[end+1]) return false; flow+=mmin[end]; cost+=mmin[end]*d[end]; int now=end; while(now!=begin){ s[last[now]].c-=mmin[end];s[last[now]^1].c+=mmin[end]; now=s[last[now]].x; } return true; } void MCMF(int type){ int flow=0,cost=0; while(SPFA(flow,cost)); if(type==1) printf("%d ",flow); else printf("%d",cost); } int main(){ scanf("%d %d %d",&n,&m,&k); begin=1,end=n; int x,y,c; for(int i=1;i<=m;i++){ scanf("%d %d %d %d",&x,&y,&c,&w[i]); ins(x,y,c,0); } MCMF(1); ins(begin=0,1,k,0); for(int i=1;i<=m;i++) ins(s[2*i].x,s[2*i].y,1e9,w[i]); MCMF(2); }