Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P2754 [CTSC1999]家园 / 星际转移问题

P2754 [CTSC1999]家园 / 星际转移问题

判断是否有解可以用并查集,如果地球和月球在同一个连通块,那么就有解。考虑到答案很小,可以枚举答案,每天都可能有新的人来到终点,利用网络流的特性,在残量网络上继续跑,不断累加答案。不同的天数的某个位置的情况是不一样的,考虑将图分层,每一天的某个点可以从上一天转移而来。当答案大于人数时得到答案。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <climits>
#define INF INT_MAX
using namespace std;
const int N = 2.5e4 + 10, M = 8e4 + 10;
int n, m, k, st, ed, cur[N], d[N], p[N];
int idx = -1, hd[N], edg[M], nxt[M], wt[M];
struct Ship
{
int h, r, id[30];
}ship[30];
int find(int x)
{
return x == p[x] ? x : p[x] = find(p[x]);
}
int num(int i, int day)
{
return day * (n + 2) + i;
}
void add(int a, int b, int c)
{
nxt[++idx] = hd[a];
hd[a] = idx;
edg[idx] = b;
wt[idx] = c;
}
bool bfs()
{
memset(d, -1, sizeof(d));
d[st] = 0;
queue <int> q;
q.push(st);
cur[st] = hd[st];
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = hd[t]; ~i; i = nxt[i])
{
int ver = edg[i];
if (d[ver] == -1 && wt[i])
{
d[ver] = d[t] + 1;
cur[ver] = hd[ver];
if (ver == ed)
return true;
q.push(ver);
}
}
}
return false;
}

int find(int x, int limit)
{
if (x == ed)
return limit;
int res = 0;
for (int i = cur[x]; ~i && res < limit; i = nxt[i])
{
cur[x] = i;
int ver = edg[i];
if (d[ver] == d[x] + 1 && wt[i])
{
int t = find(ver, min(wt[i], limit - res));
if (!t) d[ver] = -1;
wt[i] -= t;
wt[i ^ 1] += t;
res += t;
}
}
return res;
}
int dinic()
{
int res = 0, flow;
while (bfs())
while (flow = find(st, INF))
res += flow;
return res;
}
int main()
{
cin >> n >> m >> k;
st = N - 2, ed = N - 1;
memset(hd, -1, sizeof(hd));
for (int i = 0; i <= n + 1; ++i)
p[i] = i;
for (int i = 0; i < m; ++i)
{
cin >> ship[i].h >> ship[i].r;
for (int j = 0; j < ship[i].r; ++j)
{
cin >> ship[i].id[j];
if (ship[i].id[j] == -1)
ship[i].id[j] = n + 1;
if (j)
p[find(ship[i].id[j - 1])] = p[find(ship[i].id[j])];
}
}
if (find(0) != find(n + 1))
{
puts("0");
return 0;
}
add(st, num(0, 0), INF);
add(num(0, 0), st, 0);
add(num(n + 1, 0), ed, INF);
add(ed, num(n + 1, 0), 0);
int day = 1, res = 0;
while (true)
{
add(num(n + 1, day), ed, INF);
add(ed, num(n + 1, day), 0);
for (int i = 0; i <= n + 1; ++i)
{
add(num(i, day - 1), num(i, day), INF);
add(num(i, day), num(i, day - 1), 0);
}
for (int i = 0; i < m; ++i)
{
int r = ship[i].r,
a = ship[i].id[(day - 1) % r],
b = ship[i].id[day % r];
add(num(a, day - 1), num(b, day), ship[i].h);
add(num(b, day), num(a, day - 1), 0);
}
res += dinic();
if (res >= k)
break;
day++;
}
cout << day;
return 0;
}