ABC241G

假设当前在确定玩家 \(p\) 是否能成为唯一的赢家。

假设 \(p\) 能赢下所有不确定的比赛,令 \(win\) 表示他赢的数量。

如果 \(win=0\) 显然他不能成为唯一的赢家,下面都假设 \(win\ge1\)

考虑网络流建图。

建立源点 \(S\),汇点 \(T\)\(A_{i,j}\) 表示玩家 \(i\)\(j\) 之间的比赛,\(B_i\) 表示玩家 \(i\)

约定 \((u,v,w)\) 表示 \(u\) 连向 \(v\) 的容量为 \(w\) 的边。

  • \(S\) 向每场比赛连边:\((S,A_{i,j},1)\)
  • 对于每场比赛 \(A_{i,j}\),如果 \(i\) 赢了,那么 \((A_{i,j},B_i,1)\),否则如果 \(j\) 赢了,那么 \((A_{i,j},B_j,1)\),否则 \((A_{i,j},B_i,1),(A_{i,j},B_j,1)\)
  • 玩家 \(p\)\(T\) 连流量为 \(win\) 的边,\((B_p,T,win)\)
  • 其余玩家向 \(T\) 连流量为 \(win-1\) 的边,\((B_i(i\ne p),T,win-1)\)

然后跑一遍最大流,看看是否满流,满流就说明存在方案使得 \(p\) 成为唯一的赢家。

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 55, inf = 0x3f3f3f3f;
int n, m;
int G[N][N];
int a[N][N], b[N];
int head[N*N], ver[N*N*N], wei[N*N*N], nxt[N*N*N], cnt;
int S, T;
int d[N*N];

void add(int u, int v, int w) {
	ver[++cnt] = v, wei[cnt] = w, nxt[cnt] = head[u], head[u] = cnt;
	ver[++cnt] = u, wei[cnt] = 0, nxt[cnt] = head[v], head[v] = cnt;
}

bool bfs() {
	memset(d, 0, sizeof d), d[S] = 1;
	queue <int> q; q.push(S);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = head[u]; i; i = nxt[i]) {
			int v = ver[i];
			if (wei[i] && !d[v]) {
				d[v] = d[u] + 1;
				q.push(v);
				if (v == T) return true;
			}
		}
	}
	return false;
}

int dinic(int u, int flow) {
	if (u == T) return flow;
	int res = flow;
	for (int i = head[u]; i && res; i = nxt[i]) {
		int v = ver[i], w = wei[i];
		if (w && d[v] == d[u] + 1) {
			int k = dinic(v, min(flow, w));
			if (!k) d[v] = 0;
			wei[i] -= k, wei[i ^ 1] += k;
			res -= k;
		}
	}
	return flow - res;
}

bool check(int x) {
	memset(head, 0, sizeof head), cnt = 1;
	int win = 0;
	for (int i = 1; i <= n; ++i) {
		if (i == x) continue;
		if (G[x][i] != -1) ++win;
	}
	if (!win) return false;
	for (int i = 1; i <= n; ++i)
		for (int j = i + 1; j <= n; ++j)
			add(S, a[i][j], 1);
	for (int i = 1; i <= n; ++i)
		for (int j = i + 1; j <= n; ++j) {
			if (G[i][j] == 1) add(a[i][j], b[i], 1);
			else if (G[i][j] == -1) add(a[i][j], b[j], 1);
			else add(a[i][j], b[i], 1), add(a[i][j], b[j], 1);
		}
	for (int i = 1; i <= n; ++i)
		if (x == i) add(b[i], T, win);
		else add(b[i], T, win - 1);
	int sum = 0, flow;
	while (bfs())
		while (flow = dinic(S, inf)) sum += flow;
	return sum == n * (n - 1) / 2;
}

int main() {
	scanf("%d%d", &n, &m); S = 0, T = n * (n - 1) / 2 + n + 1;
	int tot = 0;
	for (int i = 1; i <= n; ++i)
		for (int j = i + 1; j <= n; ++j)
			a[i][j] = ++tot;
	for (int i = 1; i <= n; ++i) b[i] = ++tot;
	for (int i = 1, u, v; i <= m; ++i) scanf("%d%d", &u, &v), G[u][v] = 1, G[v][u] = -1;
	for (int i = 1; i <= n; ++i) if (check(i)) printf("%d ", i);
	return 0;
}
posted @ 2022-11-09 15:47  Kobe303  阅读(15)  评论(0编辑  收藏  举报