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

 
题解:
时间显然具有可二分性
按某个时间t将图分为t层,每天一层
如果u到v有一条边权为c的边,则对于u的每个时间点都向v的下一个时间点连一条容量为c的边
然后对于每个点的每个时间都向这个点的下一个时间连容量为inf的边
从S向1号点的第一天连容量为总人数的边,从每天的n号点向T连容量为inf的边
如果最大流=总人数,则此时间合法
code:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define maxn 10010 
 7 #define maxm 60000
 8 #define inf 1061109567
 9 using namespace std;
10 char ch;
11 bool ok;
12 void read(int &x){
13     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
14     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
15     if (ok) x=-x;
16 }
17 int n,m,t,u[maxm],v[maxm],c[maxm],l,r,mid;
18 struct flow{
19     int s,t,tot,now[maxn],son[maxm],pre[maxm],val[maxm];
20     int dis[maxn],head,tail,list[maxn];
21     bool bo[maxn];
22     void init(){s=0,t=maxn-1,tot=1,memset(now,0,sizeof(now));}
23     void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
24     void add(int a,int b,int c){put(a,b,c),put(b,a,0);}
25     bool bfs(){
26         memset(bo,0,sizeof(bo));
27         head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1;
28         while (head<tail){
29             int u=list[++head];
30             for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
31                 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v;
32         }
33         return bo[t];
34     }
35     int dfs(int u,int rest){
36         if (u==t) return rest;
37         int ans=0;
38         for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p])
39             if (val[p]&&dis[v]==dis[u]+1){
40                 int d=dfs(v,min(rest,val[p]));
41                 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d;
42             }
43         if (!ans) dis[u]=-1;
44         return ans;
45     }
46     int dinic(){
47         int ans=0;
48         while (bfs()) ans+=dfs(s,inf);
49         return ans;
50     }
51 }f;
52 bool check(int lim){
53     f.init();
54     f.add(f.s,1,t);
55     for (int i=1;i<=m;i++) for (int j=1;j<=lim;j++) f.add(u[i]+(j-1)*n,v[i]+j*n,c[i]);
56     for (int i=1;i<n;i++) for (int j=1;j<=lim;j++) f.add(i+(j-1)*n,i+j*n,inf);
57     for (int i=1;i<=lim+1;i++) f.add(i*n,f.t,inf);
58     return f.dinic()==t;
59 }
60 int main(){
61     read(n),read(m),read(t);
62     for (int i=1;i<=m;i++) read(u[i]),read(v[i]),read(c[i]);
63     for (l=1,r=n+t,mid=(l+r)>>1;l<r;mid=(l+r)>>1) if (check(mid)) r=mid; else l=mid+1;
64     printf("%d\n",l);
65     return 0;
66 }

 

posted @ 2016-01-18 09:41  chenyushuo  阅读(213)  评论(0编辑  收藏  举报