题意:有n支球队进行比赛,每只队伍需要打的比赛数目相同。每场比赛恰好一支队伍胜,另一支败。给出每支队伍目前胜的场数和败的场数,以及每两个队伍还剩下的比赛场数,确定所有可能的冠军的球队(获胜常数最多的的冠军,可以并列)。
思路:让i在所有队伍中取胜,设总共赢的场数为sum,那么剩下的队伍j最多只能赢sum - w[j],建立附加源点汇点,u,v之间有比赛的话,建立一个比赛节点,比赛节点连向u,v,容量为比赛场数,源点指向比赛节点,容量也为比赛场数,u,v再指向汇点容量为他们最多还能胜利的场数,如果最大流等于还剩下的场数,那么i队伍是可能胜利的
思路:让i在所有队伍中取胜,设总共赢的场数为sum,那么剩下的队伍j最多只能赢sum - w[j],建立附加源点汇点,u,v之间有比赛的话,建立一个比赛节点,比赛节点连向u,v,容量为比赛场数,源点指向比赛节点,容量也为比赛场数,u,v再指向汇点容量为他们最多还能胜利的场数,如果最大流等于还剩下的场数,那么i队伍是可能胜利的
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
const int INF = 1e8;
const int maxn = 500;
using namespace std;
struct P {
int to, cap, rev;
P(int t, int c, int r) : to(t), cap(c), rev(r) {}
};
int n, m, num, p[30];
int s, t, T, w[30];
int now[30][30], ans[30];
int lv[maxn], it[maxn];
vector<P> G[maxn];
void add(int from, int to, int cap) {
G[from].push_back(P(to, cap, G[to].size()));
G[to].push_back(P(from, 0, G[from].size() - 1));
}
bool bfs() {
memset(lv, -1, sizeof(lv));
lv[s] = 0;
queue<int> q; q.push(s);
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = 0; i < G[u].size(); i++) {
P &e = G[u][i];
if(lv[e.to] != -1 || !e.cap) continue;
lv[e.to] = lv[u] + 1;
q.push(e.to);
}
}
return lv[t] != -1;
}
int dfs(int u, int f) {
if(u == t) return f;
for(int &i = it[u]; i < G[u].size(); i++) {
P &e = G[u][i];
if(lv[e.to] <= lv[u] || !e.cap) continue;
int c = dfs(e.to, min(f, e.cap));
if(!c) continue;
G[u][i].cap -= c;
G[e.to][e.rev].cap += c;
return c;
}
return 0;
}
int dinic() {
int f = 0, fl;
while(1) {
if(!bfs()) return f;
memset(it, 0, sizeof(it));
while((fl = dfs(s, INF)) > 0) f += fl;
}
}
bool win(int id, int tal) {
int st = 1, sum = 0;
for(int i = 0; i < maxn; i++)
G[i].clear();
for(int i = 1; i <= n; i++) {
if(i == id) continue;
for(int j = i + 1; j <= n; j++) {
if(!now[i][j] || j == id) continue;
sum += now[i][j];
add(s, st, now[i][j]);
add(st, i + m, now[i][j]);
add(st, j + m, now[i][j]);
st++;
}
if(w[i] > tal) return false;
add(i + m, t, tal - w[i]);
}
int maxf = dinic();
if(maxf == sum) return true;
return false;
}
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d %d", &w[i], &m);
m = num = 0;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
scanf("%d", &now[i][j]);
if(now[i][j]) m++;
}
}
m /= 2;
s = 0; t = n + m + 1;
for(int i = 1; i <= n; i++) {
int sum = w[i];
for(int j = 1; j <= n; j++) sum += now[i][j];
if(win(i, sum)) ans[num++] = i;
}
for(int i = 0; i < num; i++)
printf("%d%c", ans[i], i < num - 1 ? ' ' : '\n');
}
return 0;
}