1. 程式人生 > >[SDOI2009]晨跑,洛谷P2153,最小費用最大流

[SDOI2009]晨跑,洛谷P2153,最小費用最大流

正題

       給出n個點,m條邊,每條邊有個長度,且只能走一次,讓你規劃一種方案,使得1到n的路徑條數最多而且總路程最短。

       很明顯這是一道網路流的題目,我們只要把每一條邊的長度改成費用,流量為1,即可。

        沒有用zkw網路流寫法。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;

struct edge{
	int x,y,next,c,cos;
}s[40410];
int n,m;
int len=1;
int begin,end;
int d[410],mmin[410],last[410],first[410];
bool tf[410];
queue<int> f;

void ins(int x,int y,int c,int cos){
	len++;
	s[len]=(edge){x,y,first[x],c,cos};first[x]=len;
}

bool SPFA(int &cost,int&flow){
	memset(d,63,sizeof(d));
	memset(tf,false,sizeof(tf));
	memset(mmin,63,sizeof(mmin));
	memset(last,0,sizeof(last));
	f.push(begin);d[begin]=0;tf[begin]=true;
	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){
				mmin[y]=min(mmin[x],s[i].c);
				d[y]=d[x]+s[i].cos;
				last[y]=i;
				if(!tf[y]){
					tf[y]=true;
					f.push(y);
				}
			}
		}
	}
	if(d[end]==d[end+1]) return false;
	cost+=d[end]*mmin[end];
	flow+=mmin[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 cost=0,flow=0;
	while(SPFA(cost,flow));
	printf("%d %d\n",flow,cost);
}

int main(){
	scanf("%d %d",&n,&m);
	begin=0,end=2*n+1;
	int x,y,c;
	for(int i=1;i<=m;i++){
		scanf("%d %d %d",&x,&y,&c);
		ins(x,y+n,1,c);
		ins(y+n,x,0,-c);
	}
	for(int i=1;i<=n;i++){
		ins(i+n,i,1,0);
		ins(i,i+n,0,0);
	}
	ins(begin,1,1e9,0);ins(n+n,end,1e9,0);
	MCMF();
}