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;
}
posted @ 2022-09-15 16:43  qingyanng  阅读(17)  评论(0编辑  收藏  举报