[luoguP2754] 星际转移问题(最大流)

传送门

 

不同的时间每个飞船所在的地点不同,给我们启示按照时间构建分层图。

同一个地点 x <x, dayi - 1> -> <x, dayi> 连一条容量为 INF 的边,因为人们可以在一个地点等待

艘飞船的路径 如果 a 的下一站是 b,那么 <a, dayi - 1> -> <b, dayi> 连一条容量为该飞船容量的边,表示可以 a 坐飞船到 b

增加超级源点 s,s 和地球连一条容量为 k 的边

增加超级汇点 t,月球的每一天都和 t 连一条容量为 INF 的边

 

枚举天数,跑最大流,直到 max_flow == k,输出天数

对于判断是否能到达,用并查集判断连通性

 

——代码

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #define N 1000001
  6 #define INF 1e9
  7 #define min(x, y) ((x) < (y) ? (x) : (y))
  8 
  9 int n, m, k, s, t, cnt, sum;
 10 int f[N], c[N], p[N], b[101][101], dis[N];
 11 int head[N], to[N << 1], next[N << 1], val[N << 1];
 12 
 13 inline int C(int t, int x)
 14 {
 15     return t * (n + 2) + x;
 16 } 
 17 
 18 inline int read()
 19 {
 20     int x = 0, f = 1;
 21     char ch = getchar();
 22     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
 23     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
 24     return x * f;
 25 }
 26 
 27 inline int find(int x)
 28 {
 29     return x == f[x] ? x : f[x] = find(f[x]);
 30 }
 31 
 32 inline void add(int x, int y, int z)
 33 {
 34     to[cnt] = y;
 35     val[cnt] = z;
 36     next[cnt] = head[x];
 37     head[x] = cnt++;
 38 }
 39 
 40 inline bool bfs()
 41 {
 42     int i, u, v;
 43     std::queue <int> q;
 44     memset(dis, -1, sizeof(dis));
 45     q.push(s);
 46     dis[s] = 0;
 47     while(!q.empty())
 48     {
 49         u = q.front(), q.pop();
 50         for(i = head[u]; i ^ -1; i = next[i])
 51         {
 52             v = to[i];
 53             if(val[i] && dis[v] == -1)
 54             {
 55                 dis[v] = dis[u] + 1;
 56                 if(v == t) return 1;
 57                 q.push(v);
 58             }
 59         }
 60     }
 61     return 0;
 62 }
 63 
 64 inline int dfs(int u, int maxflow)
 65 {
 66     if(u == t) return maxflow;
 67     int v, d, ret = 0;
 68     for(int i = head[u]; i ^ -1; i = next[i])
 69     {
 70         v = to[i];
 71         if(val[i] && dis[v] == dis[u] + 1)
 72         {
 73             d = dfs(v, min(val[i], maxflow - ret));
 74             ret += d;
 75             val[i] -= d;
 76             val[i ^ 1] += d;
 77             if(ret == maxflow) return ret;
 78         }
 79     }
 80     if(ret ^ maxflow) dis[u] = -1;
 81     return ret;
 82 }
 83 
 84 int main()
 85 {
 86     int i, j, x, y, d;
 87     n = read();
 88     m = read();
 89     k = read();
 90     s = N - 1, t = N - 2;
 91     for(i = 1; i <= n + 2; i++) f[i] = i;
 92     for(i = 1; i <= m; i++)
 93     {
 94         c[i] = read();
 95         p[i] = read();
 96         for(j = 0; j < p[i]; j++)
 97         {
 98             b[i][j] = read() + 2;
 99             if(j)
100             {
101                 x = find(b[i][j - 1]);
102                 y = find(b[i][j]);
103                 if(x ^ y) f[x] = y;
104             }
105         }
106     }
107     if(find(1) ^ find(2))
108     {
109         printf("0\n");
110         return 0;
111     }
112     d = 0;
113     memset(head, -1, sizeof(head));
114     add(s, 2, k);
115     add(2, s, 0);
116     while(1)
117     {
118         d++;
119         for(i = 1; i <= n + 2; i++)
120         {
121             add(C(d - 1, i), C(d, i), INF);
122             add(C(d, i), C(d - 1, i), 0);
123         }
124         for(i = 1; i <= m; i++)
125         {
126             add(C(d - 1, b[i][(d - 1) % p[i]]), C(d, b[i][d % p[i]]), c[i]);
127             add(C(d, b[i][d % p[i]]), C(d - 1, b[i][(d - 1) % p[i]]), 0);
128         }
129         add(C(d, 1), t, INF);
130         add(t, C(d, 1), 0);
131         while(bfs()) sum += dfs(s, INF);
132         if(sum == k)
133         {
134             printf("%d\n", d);
135             return 0;
136         }
137     }
138 }
View Code

 

posted @ 2017-06-13 14:18  zht467  阅读(146)  评论(0编辑  收藏  举报