2022杭电多校10 1 Winner Prediction (建图, 最大流)
http://acm.hdu.edu.cn/showproblem.php?pid=7244
题意: n个人两两比赛,有m1场结果已知,m2场只知道比赛双方,不知道结果。 胜场最多的一些人赢,没有平局。问1能不能赢。
思路:
- 对于a[1],他参加的未知结果的比赛一定获胜,设他胜a[1]场次,那么其他人已经胜a[i]场,最多还能胜bi = a1 - ai场。
- 建立网络流图:让m2比赛代表的一个点u连这个比赛的参赛人员x和y容量都为1,s-u的流量为1.这样保证x和y其中一人获胜。让每个参赛人员点x,向汇点t容量限制为bi,因为i最多再赢bi场,也就是最多接受bi的流量,他们最多流出bi流量。这样想要一套合法的比赛,就要最大流等于源点S的满流。 求得最大流若小于源点S的满流说明一些xi-t的边需要扩大容量,即bi增加,也就是i只能赢的比a1多。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<int, int>
//#define int long long
const int N = 2e3 + 5;
const int M = 1e4;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double PI = acos(-1.0);
int a[N];
int h[N], e[M], ne[M]; ll w[M]; int idx;
int S, T;
int d[N], cur[N];
void add( int a, int b, int c ) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
e[idx] = a, w[idx] = 0, ne[idx] = h[b], h[b] = idx ++;
}
bool bfs() {
queue<int> q;
memset(d, -1, sizeof d);
q.push(S), d[S] = 0, cur[S] = h[S];
while( !q.empty() ) {
int u = q.front(); q.pop();
for ( int i = h[u]; ~i; i = ne[i] ) {
int v = e[i];
if (d[v] == -1 && w[i]) { // 满流的边不能走
d[v] = d[u] + 1;
cur[v] = h[v];
if(v == T) return 1;
q.push(v);
}
}
}
return 0;
}
int find(int u, ll limit) {
if (u == T) return limit;
ll flow = 0;
for ( int i = cur[u]; ~i && flow < limit; i = ne[i] ) {
cur[u] = i;
int v = e[i];
if(d[v] == d[u] + 1 && w[i]) {
int tmp = find(v, min(w[i], limit - flow));
if(!tmp) d[v] = -1;
w[i] -= tmp, w[i^1] += tmp, flow += tmp;
}
}
return flow;
}
int dinic() {
int r = 0, flow;
while(bfs()) while( flow = find(S, INF) ) r += flow;
return r;
}
void solve() {
int nn, m1, m2; scanf("%d%d%d",&nn,&m1,&m2);
for ( int i = 1; i <= nn; ++ i ) a[i] = 0;
for ( int i = 0; i <= (m2 + nn) << 1; ++ i ) h[i] = -1;
idx = 0;
for ( int i = 1; i <= m1; ++ i ) {
int x, y, z; scanf("%d%d%d",&x,&y,&z);
if(z) ++ a[x]; else ++ a[y];
}
int tot = nn;
for ( int i = 1; i <= m2; ++ i ) {
int x, y; cin >> x >> y;
if (x == 1 || y == 1) {
++ a[1];
} else {
++ tot;
add(0, tot, 1);
add(tot, x, 1); add(tot, y, 1);
}
}
for ( int i = 2; i <= nn; ++ i ) {
if (a[1] - a[i] < 0) {
printf("NO\n"); return;
}
add(i, tot + 1, a[1] - a[i]);
}
S = 0, T = tot + 1;
if (dinic() == tot - nn) {
printf("YES\n");
} else printf("NO\n");
}
int main() {
int t; scanf("%d",&t);
while( t -- ) solve();
return 0;
}