AT4505 [AGC029F] Construction of a tree

https://www.luogu.com.cn/problem/AT4505

考虑建图,每个集合连向集合内的点,连出一个二分图
得到完美匹配后必定有一个点没有被匹配

把这个点拿出来,找和它相连的没有被访问过集合,假设为 v v v,它的匹配点为 p [ v ] p[v] p[v],那么就连边
u − > p [ v ] u->p[v] u>p[v], 然后把 p [ v ] p[v] p[v]拿出来,递归处理

具体实现可以强制第一个点为剩下哪个点

正确性显然,但是又怎么能想到呢?

code:

#include<bits/stdc++.h>
#define N 400050
using namespace std;
const int inf = 1e9;
struct edge {
    int v, nxt, c;
} e[N << 1];
int p[N], eid;
void init() {
    memset(p, -1, sizeof p);
    eid = 0;
}
void insert(int u, int v, int c) {
    e[eid].v = v;
    e[eid].c = c;
    e[eid].nxt = p[u];
    p[u] = eid ++;
}
void add(int u, int v, int c) {
    insert(u, v, c);
    insert(v, u, 0);
}
int S, T, d[N];
queue<int> q;
int bfs() {
    for(int i = 0; i <= T; i ++) d[i] = -1;
    d[S] = 0; q.push(S);
    while(q.size()) {
        int u = q.front(); q.pop();
        for(int i = p[u]; i + 1; i = e[i].nxt) {
            int v = e[i].v, c = e[i].c;
            if(c && d[v] == -1) {
                d[v] = d[u] + 1;
                q.push(v);
            }
        }
    }
    return d[T] != -1;
}
int dfs(int u, int flow) {
    if(u == T) return flow;
    int ret = 0;
    for(int i = p[u]; i + 1; i = e[i].nxt) {
        int v = e[i].v, c = e[i].c;
        if(c && d[v] == d[u] + 1) {
            int tmp = dfs(v, min(flow, c));
            e[i].c -= tmp, e[i ^ 1].c += tmp;
            flow -= tmp, ret += tmp;
            if(!flow) break;
        }
    }
    if(!ret) d[u] = -1;
    return ret;
}
int Dinic() {
    int ret = 0;
    for(; bfs() ;) ret += dfs(S, inf);
    return ret;
}
int to[N], vis[N], n;
vector<int> g[N];
pair<int, int> ans[N];
int solve() {
    for(int u = 2; u <= n; u ++) {
        for(int i = p[u]; i + 1; i = e[i].nxt) {
            int v = e[i].v, c = e[i].c;
            if(v == S) continue;
            if(!c) to[v - n] = u;
        }
    }
   // for(int i = 1; i < n; i ++) printf("%d ", to[i]); printf("\n");
    q.push(1);
    int gs = 0;
    while(q.size()) {
        int u = q.front(); q.pop();
        //printf("%d ", u);
        for(int v : g[u]) {
            if(vis[v]) continue;
            ans[v] = make_pair(u, to[v]);
            vis[v] = 1;
            q.push(to[v]);
            gs ++;
        }
    }
    return gs == n - 1;
}
int main() {
    init();
    scanf("%d", &n);
    S = 2 * n + 1, T = S + 1;
    for(int i = 1; i < n; i ++) {
        int gs, x;
        scanf("%d", &gs);
        while(gs --) {
            scanf("%d", &x);
            if(x != 1) add(x, i + n, 1);
            g[x].push_back(i);
        }
    }
    for(int i = 2; i <= n; i ++) add(S, i, 1);
    for(int i = 1; i < n; i ++) add(i + n, T, 1);
    if(Dinic() != n - 1) {
        printf("-1");
        return 0;
    }
     if(!solve()) {
        printf("-1");
        return 0;
     }
    for(int i = 1; i < n; i ++) printf("%d %d\n", ans[i].first, ans[i].second);
    return 0;
}
posted @ 2021-12-06 19:47  lahlah  阅读(32)  评论(0编辑  收藏  举报