codeforces 589F. Gourmet and Banquet 二分+网络流

题目链接

给你n种菜, 每一种可以开始吃的时间不一样, 结束的时间也不一样。 求每种菜吃的时间都相同的最大的时间。时间的范围是0-10000。

看到这个题明显可以想到网络流, 但是时间的范围明显不允许我们把对每一个时间都连边。

那么我们可以对时间的区间连边, 对于一个区间, 如果一盘菜的开始时间>=这个区间的左端点, 结束时间小于右端点, 那么这盘菜就对这个时间段连边, 权值inf。然后每个时间段对汇点t连边, 权值为这段时间的长度。 源点s向每个菜连边, 权值为二分枚举的时间长度, 然后跑最大流, 看结果是否等于n*x, x是枚举的时间。

具体对时间区间连边的方法可以看代码。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define pb(x) push_back(x)
  4 #define ll long long
  5 #define mk(x, y) make_pair(x, y)
  6 #define lson l, m, rt<<1
  7 #define mem(a) memset(a, 0, sizeof(a))
  8 #define rson m+1, r, rt<<1|1
  9 #define mem1(a) memset(a, -1, sizeof(a))
 10 #define mem2(a) memset(a, 0x3f, sizeof(a))
 11 #define rep(i, a, n) for(int i = a; i<n; i++)
 12 #define ull unsigned long long
 13 typedef pair<int, int> pll;
 14 const double PI = acos(-1.0);
 15 const double eps = 1e-8;
 16 const int mod = 1e9+7;
 17 const int inf = 1061109567;
 18 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
 19 const int maxn = 4e5+5;
 20 int q[maxn*2], head[maxn*2], dis[maxn/10], s, t, used[10005], a[105], b[105], n, cnt, num, from;
 21 struct node
 22 {
 23     int to, nextt, c;
 24     node(){}
 25     node(int to, int nextt, int c):to(to), nextt(nextt), c(c){}
 26 }e[maxn*2];
 27 void init() {
 28     num = from = cnt = 0;
 29     mem1(head);
 30 }
 31 void add(int u, int v, int c) {
 32     e[num] = node(v, head[u], c); head[u] = num++;
 33     e[num] = node(u, head[v], 0); head[v] = num++;
 34 }
 35 int bfs() {
 36     mem(dis);
 37     dis[s] = 1;
 38     int st = 0, ed = 0;
 39     q[ed++] = s;
 40     while(st<ed) {
 41         int u = q[st++];
 42         for(int i = head[u]; ~i; i = e[i].nextt) {
 43             int v = e[i].to;
 44             if(!dis[v]&&e[i].c) {
 45                 dis[v] = dis[u]+1;
 46                 if(v == t)
 47                     return 1;
 48                 q[ed++] = v;
 49             }
 50         }
 51     }
 52     return 0;
 53 }
 54 int dfs(int u, int limit) {
 55     if(u == t) {
 56         return limit;
 57     }
 58     int cost = 0;
 59     for(int i = head[u]; ~i; i = e[i].nextt) {
 60         int v = e[i].to;
 61         if(e[i].c&&dis[v] == dis[u]+1) {
 62             int tmp = dfs(v, min(limit-cost, e[i].c));
 63             if(tmp>0) {
 64                 e[i].c -= tmp;
 65                 e[i^1].c += tmp;
 66                 cost += tmp;
 67                 if(cost == limit)
 68                     break;
 69             } else {
 70                 dis[v] = -1;
 71             }
 72         }
 73     }
 74     return cost;
 75 }
 76 int dinic() {
 77     int ans = 0;
 78     while(bfs()) {
 79         ans += dfs(s, inf);
 80     }
 81     return ans;
 82 }
 83 int check(int x) {
 84     init();
 85     for(int i = 0; i<10001; i++) {
 86         if(used[i]) {
 87             int flag = 1;
 88             for(int j = 0; j<n; j++) {
 89                 if(a[j]<=from&&i<=b[j]) {
 90                     if(flag) {
 91                         add(s, ++cnt, i-from);          //起点对区间连边。
 92                         flag = 0;
 93                     }
 94                     add(cnt, j+300, inf);               //区间对每一个在它范围内的菜连边
 95                 }
 96             }
 97             from = i;
 98         }
 99     }
100     for(int i = 0; i<n; i++) {
101         add(i+300, t, x);
102     }
103     int ans = dinic();
104     if(ans == x*n)
105         return 1;
106     return 0;
107 }
108 int main()
109 {
110     cin>>n;
111     for(int i = 0; i<n; i++) {
112         scanf("%d%d", &a[i], &b[i]);
113         used[a[i]] = 1;
114         used[b[i]] = 1;
115     }
116     s = 0, t = 402;
117     int l = 0, r = 10001;
118     while(r>l+1) {
119         int mid = l+r>>1;
120         if(check(mid)) {
121             l = mid;
122         } else {
123             r = mid;
124         }
125     }
126     cout<<l*n<<endl;
127 }
原文地址:https://www.cnblogs.com/yohaha/p/5033680.html