【[JSOI2008]Blue Mary的旅行】分层图最大流
最近学习了网络流,这两天暂时从令人自闭的数学和诡异字符串和死都调不出来的数据结构中放松了出来。
对于原题,我们很容易想到是一个网络流模型,看到这个最大值最小,我们能够想到二分。然后呢,我们还要考虑到这个限制条件--每天只能走一步。那么其实我们对于每一天分层就可以了,上一天的点向下一条边的点连边,分成若干天层,如果在分层图下最大流能跑出t个人,也就满足了题意。
再一深思,我们发现,其实二分很麻烦,每次边都要重构一下,原来跑出来的信息都不能保留。那么我们迭代加深的每次新建图,再跑最大流就可以了。
题目描述
在一段时间之后,网络公司终于有了一定的知名度,也开始收到一些订单,其中最大的一宗来自B市。 Blue Mary决定亲自去签下这份订单。为了节省旅行经费,他的某个金融顾问建议只购买U航空公司的机票。U航空公司的所有航班每天都只有一班,并且都是上午出发当天下午到达的,所以他们每人每天只能坐一班飞机。 经过调查,他们得到了U航空公司经营的所有航班的详细信息,这包括每一航班的出发地,目的地以及最多能买到的某一天出发的票数。(注意: 对于一个确定的航班,无论是哪一天,他们最多能买到的那一天出发的票数都是相同的。) Blue Mary注意到他们一定可以只乘坐U航空公司的航班就从A市到达B市,但是,由于每一航班能买到的票的数量的限制,他们所有人可能不能在同一天到达B市。 所以现在Blue Mary需要你的帮助,设计一个旅行方案使得最后到达B市的人的到达时间最早。输入输出格式
输入格式: 第一行包含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的机票。) 输入保证从一个城市到另一个城市的单向航班最多只有一个。 输出格式: 仅有一行,包含一个正整数,表示最后到达B市的人的最早到达时间。假设他们第一次乘飞机的那一天是第一天。输入输出样例
说明
约定: 2 <= N <= 50 1 <= M <= 2450 1 <= T <= 50 1 <= X,Y <= N X != Y 1 <= Z <= 50#include<stdio.h> #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<queue> using namespace std; const int maxm = 500005; int en[maxm],nt[maxm],la[maxm],owo=1,v[maxm]; void adg(int x,int y,int z) { en[++owo]=y; nt[owo]=la[x]; la[x]=owo; v[owo]=z; en[++owo]=x; nt[owo]=la[y]; la[y]=owo; v[owo]=0; } int tot; int n,m,t,S,T; int X[2555],Y[2555],Z[2555]; int dis[maxm],cnt[maxm]; int sap(int x,int flow) { if(x==T) return flow; int dlt = 0; for(int it=la[x];it;it=nt[it]) { int y = en[it]; if(v[it]&&dis[y]+1==dis[x]) { int tmp = sap(y,min(flow-dlt,v[it])); v[it]-=tmp; v[it^1]+=tmp; dlt +=tmp; if(dlt==flow||dis[S]>=tot) return dlt; } } cnt[dis[x]]--; if(cnt[dis[x]]==0) dis[S] = tot; dis[x]++; cnt[dis[x]]++; return dlt; } int getmaxflow() { for(int i=0;i<=tot;i++) cnt[i]=dis[i]=0; int sm = 0; while(dis[S]<tot) sm+=sap(S,0x3f3f3f3f); return sm; } int DY[205][105]; int main() { scanf("%d%d%d",&n,&m,&t); S = ++tot; T = ++tot; for(int i=1;i<=m;i++) { scanf("%d%d%d",&X[i],&Y[i],&Z[i]); } for(int i=1;i<=n;i++) DY[0][i] = ++tot; adg(S,DY[0][1],t); adg(DY[0][n],T,t); int flow = 0; for(int tim=1;;tim++) { for(int i=1;i<=n;i++) DY[tim][i] = ++tot,adg(DY[tim-1][i],tot,0x3f3f3f3f); for(int i=1;i<=m;i++) { adg(DY[tim-1][X[i]],DY[tim][Y[i]],Z[i]); } adg(DY[tim][n],T,t); flow += getmaxflow(); if(flow==t) { printf("%d",tim); exit(0); } } }