Codeforces

https://codeforces.com/contest/1198/problem/C

要选取一个大小大于等于n的匹配或者选取一个大小大于等于n的独立集。

考虑不断加入匹配集,最终加入了x条边。

那么剩下的点之间是没有边可以加的,否则匹配数还会增加,也就是剩下的点要么没有边可以连,要么这些边去往的点都在匹配里面。

考虑x>=n,之间输出。

否则x<n,则剩下的点至少有3n-2x个,这些全部选上也>=n,连匹配里面的点都不需要动(因为匹配里面的点可能会和匹配外的点有边连通)。

其实看见有3*n个点应该反应到是要为什么这样搞的。

#include<bits/stdc++.h>
using namespace std;

bool vis[300005];
int eid[500005], etop;

void init(int n, int m) {
    memset(vis, 0, sizeof(vis[0]) * (3*n + 1));
    etop = 0;
}

void update(int i) {
    int u, v;
    scanf("%d%d", &u, &v);
    if(vis[u] || vis[v])
        return;
    else {
        vis[u] = vis[v] = 1;
        eid[++etop] = i;
    }
}

void Matching(int n) {
    puts("Matching");
    for(int i = 1; i <= n; ++i) {
        printf("%d%c", eid[i], " 
"[i == n]);
    }
}

void IndSet(int n) {
    puts("IndSet");
    int cnt = 0;
    for(int i = 1; i <= 3 * n; ++i) {
        if(!vis[i]) {
            ++cnt;
            printf("%d%c", i, " 
"[cnt == n]);
            if(cnt == n)
                return;
        }
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int T;
    scanf("%d", &T);
    int n, m;
    while(T--) {
        scanf("%d%d", &n, &m);
        init(n, m);
        for(int i = 1; i <= m; ++i) {
            update(i);
        }
        if(etop >= n) {
            Matching(n);
        } else {
            IndSet(n);
        }
    }
}

以前没怎么接触过什么匹配、独立集,不会做才正常。

原文地址:https://www.cnblogs.com/Yinku/p/11286332.html