题目描述
由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了。
于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,
地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。
现有 n nn 个太空站位于地球与月球之间,且有 m mm 艘公共交通太空船在其间来回穿梭。
每个太空站可容纳无限多的人,而每艘太空船 i ii 只可容纳 Hi H_iHi 个人。每艘太空船将周期性地停靠一系列的太空站,
例如:{1,3,4} \{1, 3, 4 \}{1,3,4} 表示该太空船将周期性地停靠太空站 134134134 …
每一艘太空船从一个太空站驶往任一太空站耗时均为 1 11。
人们只能在太空船停靠太空站(或月球、地球)时上、下船。
初始时所有人全在地球上,太空船全在初始站。
试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。
输入格式
文件第 1 11 行有 3 33 个正整数 n nn(太空站个数)、m mm(太空船个数)和 k kk(需要运送的地球上的人的个数)。
接下来的 m mm 行给出太空船的信息。第 i+1 i + 1i+1 行说明太空船 i ii。
第 1 11 个数表示 i ii 可容纳的人数 Hi H_iHi,第 2 22 个数表示 i ii 一个周期停靠的太空站个数 r rr,(1≤r≤n+2 1 \leq r \leq n + 21≤r≤n+2),
随后 r rr 个数是停靠的太空站的编号 {Si1,Si2,…,Sir} \{ {S_i}_1, {S_i}_2, \ldots, {S_i}_r \}{Si1,Si2,…,Sir},地球用 0 00 表示,月球用 −1 -1−1 表示。
时刻 0 00 时,所有太空船都在初始站,然后开始运行。在时刻 1,2,3,… 1, 2, 3, \ldots1,2,3,… 等正点时刻各艘太空船停靠相应的太空站。
人只有在 0,1,2… 0, 1, 2 \ldots0,1,2… 等正点时刻才能上下太空船。
输出格式
输出全部人员安全转移所需的时间。如果无解,则输出 0 00。
样例
样例输入
2 2 1
1 3 0 1 2
1 3 1 2 –1
样例输出
5
建图好复杂,看了题解才弄懂,第一次做分层图网络流。
直接求天数是求不出来的,只能从小到大枚举天数,因为每次都是在前一天的残留网络基础上加点加边所以复杂度不高。
我们把每天的每个太空站以及地球和月亮都作为一个点,对于第i天,源点s和i*n+2也就是地球建一容量为INF的边,
i*n+1也就是月亮和汇点建容量为INF的边,而对于每个太空船前一天所在太空站(i-1)*n+a[i][(j-1)%len[i]]和今天所在太空站
i*n+a[i][j%len[i]]建一容量为太空船容量的边,从小到大枚举天数,知道每天的最大流之和大于等于k就是最小天数了。
#include<stdio.h> #include<algorithm> #include<string.h> #include<queue> using namespace std; const int maxm = 1000000; const int INF = 1e9 + 7; struct node { int v, flow, next; }edge[maxm]; int head[maxm], dis[maxm], cur[maxm], flag[maxm]; int a[105][105], len[maxm], b[105]; int cnt, s, t, n, m; void init() { cnt = 0, s = 0, t = 100000; memset(head, -1, sizeof(head)); } void add(int u, int v, int w) { edge[cnt].v = v, edge[cnt].flow = w, edge[cnt].next = head[u], head[u] = cnt++; edge[cnt].v = u, edge[cnt].flow = 0, edge[cnt].next = head[v], head[v] = cnt++; } int bfs() { memset(dis, -1, sizeof(dis)); dis[s] = 0; queue<int>q; q.push(s); while (!q.empty()) { int u = q.front();q.pop(); for (int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].v; if (dis[v] == -1 && edge[i].flow>0) { dis[v] = dis[u] + 1; q.push(v); } } } if (dis[t] == -1) return 0; return 1; } int dfs(int u, int flow) { if (u == t) return flow; for (int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].v; if (dis[v] == dis[u] + 1 && edge[i].flow) { int d = dfs(v, min(flow, edge[i].flow)); if (d > 0) { edge[i].flow -= d, edge[i ^ 1].flow += d; return d; } } } return 0; } int dinic() { int ans = 0, d; while (bfs()) { while (d = dfs(s, INF)) ans += d; } return ans; } int main() { int i, j, k; scanf("%d%d%d", &n, &m, &k); n += 2; init(); for (i = 1;i <= m;i++) { scanf("%d", &b[i]); scanf("%d", &len[i]); for (j = 0;j < len[i];j++) { scanf("%d", &a[i][j]); a[i][j] += 2; } } int ans = 0, sum = 0; while (1) { if (ans == 100) break; add(ans*n + 1, t, INF); add(s, ans*n + 2, INF); if (ans != 0) { for (i = 1;i <= n;i++) add((ans - 1)*n + i, ans*n + i, INF); for (i = 1;i <= m;i++) { int x = a[i][(ans - 1) % len[i]]; int y = a[i][ans%len[i]]; add((ans - 1)*n + x, ans*n + y, b[i]); } } sum += dinic(); if (sum >= k) break; ans++; } if (ans == 100) printf("0\n"); else printf("%d\n", ans); return 0; }