P1264题解
- 原题连接
题目大意
给你一个球队现在的胜利场次(失败场次屁用没有),以及没有进行的比赛
建模
很明显,一个队跑一次最大流,当前队(现在跑网络流的队伍)能夺冠的条件就是其他队的胜利数都小于等于当前队的最大胜利数(废话)。
我们将当前队的最大胜利数表示为
将每场比赛离散化一下,从源点向每个比赛连边,每个比赛向两个队连边,流量都为这两个队比赛的次数
每个队向汇点连边,流量为当前队(设当前队为
最后只要判断最大流是不是当前队的最大胜利次数即可。
注意:
- 不要自己打自己。
- 不要连负流量的边。
- 不要忘记当前弧优化。
Code
#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);
}