1. 程式人生 > 其它 >L3-3 勝利者集合(天梯賽)

L3-3 勝利者集合(天梯賽)

這個題知道是最大流 但是比賽的時候就是不知道怎麼建圖

#include <bits/stdc++.h>
using namespace std;
const int N = 1500, M = 10010, INF = 1e9;

int n, m, S, T;
struct Edge {
    int to, nxt, flow;
}line[M];
int fist[N], idx, d[N], cur[N];

void add(int x, int y, int z) {
    line[idx] = {y, fist[x], z}; fist[x] = idx ++;
    line[idx] = {x, fist[y], 0}; fist[y] = idx ++;
}

bool bfs() {
    queue<int> q;
    memset(d, -1, sizeof d);    
    q.push(S), d[S] = 0, cur[S] = fist[S];
    while(!q.empty()) {
        int u = q.front(); q.pop();
        for(int i = fist[u]; i != -1; i = line[i].nxt) {
            int v = line[i].to;
            if(d[v] == -1 && line[i].flow) {
                d[v] = d[u] + 1;
                cur[v] = fist[v];
                if(v == T) return 1;
                q.push(v); 
            }
        }
    }
    return 0;
}

int find(int u, int limit) {
    if(u == T) return limit;
    int flow = 0;
    for(int i = cur[u]; i != -1 && flow < limit; i = line[i].nxt) {
        cur[u] = i;
        int v = line[i].to;
        if(d[v] == d[u] + 1 && line[i].flow) {
            int t = find(v, min(line[i].flow, limit - flow));
            if(!t) d[v] = -1;
            line[i].flow -= t;
            line[i ^ 1].flow += t;
            flow += t;
        }
    }
    return flow;
}

int dinic() {
    int res = 0, flow;
    while(bfs()) while(flow = find(S, INF)) res += flow;
    return res;
}

int main() {
    ios::sync_with_stdio(0); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> m;
    vector<vector<int>> g(n, vector<int>(n, 0));
    for(int i = 0; i < m; ++ i) {
        int u, v;
        cin >> u >> v;
        u --, v --;
        g[u][v] = 1, g[v][u] = -1;
    }
    S = n + (n - 2) * (n - 1) / 2;
    T = S + 1;
    int flag = 0;
    for(int i = 0; i < n; ++ i) {
        int win = n - 1;
        for(int j = 0; j < n; ++ j) 
            if(g[i][j] == -1) win --;
        idx = 0;
        memset(fist, -1, sizeof fist);
        int cur = n;
        for(int j = 0; j < n; ++ j) {
            if(j == i) continue;
            for(int k = j + 1; k < n; ++ k) {
                if(k == i) continue;
                add(S, cur, 1);
                if(g[j][k] == 0) {
                    add(cur, j, 1);
                    add(cur, k, 1);
                }
                if(g[j][k] == 1)
                    add(cur, j, 1);
                if(g[j][k] == -1)
                    add(cur, k, 1);
                cur ++;
            }
        }
        bool ok = true;
        for(int j = 0; j < n; ++ j) {
            if(win - 1 - (g[j][i] > 0) < 0) {
                ok = false;
                break;
            }
            if(j != i) 
                add(j, T, win - 1 - (g[j][i] > 0));
        }
        if(!ok) continue;
        if(dinic() == (n - 1) * (n - 2) / 2) {
            if(flag) cout << ' ';
            cout << i + 1;
            flag = 1;
        }
    }
    cout << '\n';
    return 0;
}