首页 > 代码库 > 【BZOJ1570】[JSOI2008]Blue Mary的旅行 动态加边网络流

【BZOJ1570】[JSOI2008]Blue Mary的旅行 动态加边网络流

【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的旅行 动态加边网络流