P1264题解

  1. 1. P1264 K-联赛 题解
    1. 1.1. 题目大意
    2. 1.2. 建模
    3. 1.3. Code

P1264 K-联赛 题解

题目大意

给你一个球队现在的胜利场次(失败场次屁用没有),以及没有进行的比赛 ,找出可能成为胜利次数最多的球队。

建模

很明显,一个队跑一次最大流,当前队(现在跑网络流的队伍)能夺冠的条件就是其他队的胜利数都小于等于当前队的最大胜利数(废话)。

我们将当前队的最大胜利数表示为 ,第 i 队的胜利上限为 ,则

将每场比赛离散化一下,从源点向每个比赛连边,每个比赛向两个队连边,流量都为这两个队比赛的次数

每个队向汇点连边,流量为当前队(设当前队为 )的最大胜利次数减去其他队的胜利数

最后只要判断最大流是不是当前队的最大胜利次数即可。

  • 注意:
    • 不要自己打自己。
    • 不要连负流量的边。
    • 不要忘记当前弧优化。

Code

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
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e4 + 10;
const int M = 2e4 + 10;
struct edge {
int u, v, c, val, nxt;
edge(int u = 0, int v = 0, int c = 0, int val = 0, int nxt = 0): u(u), v(v), c(c), val(val), nxt(nxt) {}
} e[M];
int cnt = 1;
int head[N];
void ADD(int u, int v, int c, int val = 0) {
cnt++;
e[cnt] = edge(u, v, c, val, head[u]);
head[u] = cnt;
}
void add_edge(int u, int v, int c, int val = 0) {
ADD(u, v, c, val);
ADD(v, u, 0, -val);
}
int dep[N];
int n;
int s, t, tot;
int now[N];
int a[100][100];
int loc[100][100];
int w[N];
bool bfs() {
memset(dep, 0, sizeof dep);
memcpy(now, head, sizeof head);
dep[s] = 1;
queue<int>q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
int c = e[i].c;
if (!c || dep[v] != 0)continue;
dep[v] = dep[u] + 1;
q.push(v);
}
}
return dep[t];
}
int dfs(int u, int t, int flow) {
if (u == t) return flow;
for (int i = now[u]; i; i = e[i].nxt) {
now[u] = i;
int v = e[i].v;
int c = e[i].c;
if (!c || dep[v] != dep[u] + 1) continue;
int ff = dfs(v, t, min(flow, c));
if (ff) return e[i].c -= ff, e[i ^ 1].c += ff, ff;
}
return 0;
}
int maxflow() {
int ans = 0;
while (bfs()) {
int nowflow;
while ((nowflow = dfs(s, t, inf))) ans += nowflow;
}
return ans;
}
void work(int x) {
cnt = 1;
memset(head, 0, sizeof head);
int mx = w[x];
int ans = 0;
for (int i = 1; i <= n; i++) mx += a[x][i];
for (int i = 1; i <= n; i++) {
if (i == x) continue;
if (w[i] > mx) return;
add_edge(i, t, mx - w[i]);
for (int j = 1; j < i; j++) {
if (j != x && a[i][j]) {
add_edge(s, loc[i][j], a[i][j]);
add_edge(loc[i][j], i, a[i][j]);
add_edge(loc[i][j], j, a[i][j]);
ans += a[i][j];
}
}
}
if (maxflow() == ans) cout << x << " ";
}
int main() {
cin >> n;
s = n + 1;
t = n + 2;
tot = t;
for (int i = 1; i <= n; i++) {
cin >> w[i];
int sb;
cin >> sb;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) loc[i][j] = ++tot;
for (int i = 1; i <= n; i++) work(i);
}