1. 程式人生 > >[ZJOI2010]網路擴容,P2604,最小費用最大流

[ZJOI2010]網路擴容,P2604,最小費用最大流

正題

      這一題想了我很久,結果發現很智障。

      原來是一個裸題啊。

      先跑最大流,然後剩下的是一個殘餘網路,容易知道如果擴容,肯定在殘餘網路裡面找路徑,因為如果不在殘餘網路裡面找路徑,那麼肯定就會多算,就相當於有流量不用。

       在殘餘網路裡面連邊,流量無限,費用是擴容費用。

        建立一個超級源點,向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);
}