1. 程式人生 > >【BZOJ1570】[JSOI2008]Blue Mary的旅行 動態加邊網絡流

【BZOJ1570】[JSOI2008]Blue Mary的旅行 動態加邊網絡流

efi 一次 第一次 dfs name jsoi2008 網絡公司 data cstring

【BZOJ1570】[JSOI2008]Blue Mary的旅行

Description

在一段時間之後,網絡公司終於有了一定的知名度,也開始收到一些訂單,其中最大的一宗來自B市。Blue Mary決定親自去簽下這份訂單。為了節省旅行經費,他的某個金融顧問建議只購買U航空公司的機票。U航空公司的所有航班每天都只有一班,並且都是上午出發當天下午到達的,所以他們每人每天只能坐一班飛機。經過調查,他們得到了U航空公司經營的所有航班的詳細信息,這包括每一航班的出發地,目的地以及最多能買到的某一天出發的票數。(註意: 對於一個確定的航班,無論是哪一天,他們最多能買到的那一天出發的票數都是相同的。) Blue Mary註意到他們一定可以只乘坐U航空公司的航班就從A市到達B市,但是,由於每一航班能買到的票的數量的限制,他們所有人可能不能在同一天到達B市。所以現在Blue Mary需要你的幫助,設計一個旅行方案使得最後到達B市的人的到達時間最早。

Input

第一行包含3個正整數N,M和T。題目中會出現的所有城市分別編號為1,2,…,N,其中城市A編號一定為1,城市B編號一定為N. U公司一共有M條(單向)航班。而連Blue Mary在內,公司一共有T個人要從A市前往B市。 以下M行,每行包含3個正整數X,Y,Z, 表示U公司的每一條航班的出發地,目的地以及Blue Mary最多能夠買到的這一航班某一天出發的票數。(即:無論是哪一天,Blue Mary最多只能買到Z張U航空公司的從城市X出發到城市Y的機票。) 輸入保證從一個城市到另一個城市的單向航班最多只有一個。

Output

僅有一行,包含一個正整數,表示最後到達B市的人的最早到達時間。假設他們第一次乘飛機的那一天是第一天。

Sample Input

3 3 5
1 2 1
2 3 5
3 1 4

Sample Output

6

HINT

約定:
2 <= N <= 50
1 <= M <= 2450
1 <= T <= 50
1 <= X,Y <= N
X != Y
1 <= Z <= 50

題解:我們假設在tim時所有人都能到達終點,於是我們枚舉tim,將每個點拆成tim個,然後連邊跑最大流,若流量=T,說明tim就是答案

具體方法:用(i,j)表示將原來的i號節點拆成第j個點
1.S -> (0,0) 流量T
2.(i,j-1) -> (i,j) 流量∞

3.對於邊(a,b,c) (a,j-1) -> (b,j) 流量c
4.(n,j) -> T 流量T

由於本人覺得點數比較多,感到很虛,所以用了動態加邊的最大流,56ms飛起~

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define P(A,B)	((B)*n+A)
using namespace std;

int to[1000000],next[1000000],val[1000000],d[50010],head[50010],pa[2500],pb[2500],pc[2500];
int n,m,t,cnt,ans,sum,S,T,tim;
queue<int> q;
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
}
int bfs()
{
	int i,u;
	memset(d,0,sizeof(d));
	while(!q.empty())	q.pop();
	d[S]=1,q.push(S);
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i!=-1;i=next[i])
		{
			if(!d[to[i]]&&val[i])
			{
				d[to[i]]=d[u]+1;
				if(to[i]==T)	return 1;
				q.push(to[i]);
			}
		}
	}
	return 0;
}
int dfs(int x,int mf)
{
	if(x==T)	return mf;
	int i,temp=mf,k;
	for(i=head[x];i!=-1;i=next[i])
	{
		if(d[to[i]]==d[x]+1&&val[i])
		{
			k=dfs(to[i],min(temp,val[i]));
			if(!k)	d[to[i]]=0;
			val[i]-=k,val[i^1]+=k,temp-=k;
			if(!temp)	break;
		}
	}
	return mf-temp;
}
int main()
{
	n=rd(),m=rd(),t=rd(),tim=n+t;
	S=0,T=n*(tim+1)+1;
	memset(head,-1,sizeof(head));
	add(S,1,t);
	int i,j,k,a,b,c;
	for(i=1;i<=m;i++)	pa[i]=rd(),pb[i]=rd(),pc[i]=rd();
	for(i=1;i<=tim;i++)
	{
		for(j=1;j<=m;j++)	add(P(pa[j],i-1),P(pb[j],i),pc[j]);
		for(j=1;j<=n;j++)	add(P(j,i-1),P(j,i),1<<30);
		add(P(n,i),T,t);
		while(bfs())	sum+=dfs(S,1<<30);
		if(sum==t)
		{
			printf("%d",i);
			return 0;
		}
	}
}

【BZOJ1570】[JSOI2008]Blue Mary的旅行 動態加邊網絡流