Blog of RuSun

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

P6054 [RC-02] 开门大吉

P6054 [RC-02] 开门大吉

每个人可以选择一套题,并且一套题可以被多个人选择,那么决策的数量即为 $n m $ 级别的,建图一定不是线性的。一个人选择一套题,相当于割一次。现在考虑怎么处理限制。如果第 $i$ 个人在 $x$ 处割,那么第 $j$ 个人必须在 $x +k$ 后面割,那么在 $(i, x) - (j, x + k)$ 连边,表示不能割。如果 $j$ 选择了前面的,那么就没有割掉。注意当 $x + k > m$ 时,是不合法的,直接向 $(j, m)$ 连边。

略微卡常,无解果断跳出。注意浮点数的处理。

查看代码
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
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const double inf = 1e9, eps = 1e-12;
const int N = 1e4 + 10, M = 2e5 + 10;
int n, m, p, o, c[N], st, ed, d[N], cur[N];
double wt[M];
int idx, hd[N], nxt[M], edg[M];
void add(int a, int b, double c)
{
nxt[++idx] = hd[a];
hd[a] = idx;
edg[idx] = b;
wt[idx] = c;
}
bool bfs()
{
for (int i = st; i <= ed; i++)
d[i] = -1;
d[st] = 0;
cur[st] = hd[st];
queue<int> q;
q.push(st);
while (!q.empty())
{
int t = q.front();
q.pop();
for (int i = hd[t]; ~i; i = nxt[i])
if (d[edg[i]] == -1 && wt[i] > eps)
{
cur[edg[i]] = hd[edg[i]];
d[edg[i]] = d[t] + 1;
if (edg[i] == ed)
return true;
q.push(edg[i]);
}
}
return false;
}
double exploit(int x, double limit)
{
if (x == ed)
return limit;
double res = 0;
for (int i = cur[x]; ~i && res < limit - eps; i = nxt[i])
{
cur[x] = i;
if (d[edg[i]] == d[x] + 1 && wt[i] > eps)
{
double t = exploit(edg[i], min(wt[i], limit - res));
if (t < eps)
d[edg[i]] = -1;
wt[i] -= t;
wt[i ^ 1] += t;
res += t;
}
}
return res;
}
double dinic()
{
double res = 0, flow;
while (res < inf + eps && bfs())
while (res < inf + eps && (flow = exploit(st, inf)) > eps)
res += flow;
return res;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d%d", &n, &m, &p, &o);
st = 0, ed = n * (m + 1) + 1;
idx = -1;
for (int i = st; i <= ed; i++)
hd[i] = -1;
for (int i = 1; i <= n; i++)
{
add(st, i, inf);
add(i, st, 0);
}
for (int i = 1; i <= p; i++)
scanf("%d", &c[i]);
for (int j = 1; j <= m; j++)
{
for (int i = 1; i <= n; i++)
{
double t = 1, res = 0;
for (int k = 1; k <= p; k++)
{
double a;
scanf("%lf", &a);
t *= a;
res += t * c[k];
}
add(j * n + i - n, j * n + i, res);
add(j * n + i, j * n + i - n, 0);
}
}
for (int a, b, k; o; o--)
{
scanf("%d%d%d", &a, &b, &k);
for (int i = 0; i <= n; i++)
{
add(i * n + b, min(m, i + k) * n + a, inf);
add(min(m, i + k) * n + a, i * n + b, 0);
}
}
for (int i = 1; i <= n; i++)
{
add(n * m + i, ed, inf);
add(ed, n * m + i, 0);
}
double t = dinic();
t < inf + eps ? printf("%lf\n", t) : puts("-1");
}
return 0;
}