bzoj1854

二分图匹配/并查集

其实我们发现,这里的方案就是希望从一开始一直能够被匹配上,那么我们就设立1-10000个点,一个装备向对应的属性连边,那么我们从1开始跑匹配,直到不能匹配结束。

但是这样很明显不是正解,我们把每个装备的两个属性之间连边,把小的属性连向大的属性,如果这两个属性已经相连,那么我们把大的属性赋值访问过,否则相连,把小的属性赋值相连,然后就是统计答案,我们找到第一个未访问的点i,答案就是i-1

原理是什么呢?引用hzwer

将每个武器变成一条边 连接两个属性

如果一个联通块形成了一棵n个点的树 那么只能满足其中的n-1个的点

如果一个联通块有一个环 那么就能满足所有的点

于是我们用并查集维护图的连通性,对于每个集合记录这个联通块有没有环,以及这个联通块中最大的点是多少

一旦某个点所在并查集中无环且最大的点是自己那么就可以输出答案了

一个联通块里如果没有环,那么最大的不能选,否则都能选,正确性显然,vis记录是否能选

#include<bits/stdc++.h>
using namespace std;
const int N = 1000010; 
int n;
int fa[N], vis[N];
inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= 10000; ++i) fa[i] = i;
    for(int i = 1; i <= n; ++i)
    {
        int u, v, x, y;
        scanf("%d%d", &u, &v);
        x = find(u);
        y = find(v);
        if(x == y) vis[x] = 1;
        else
        {
            if(x < y) swap(x, y);
            vis[y] = 1;
            fa[y] = x;
        }
    }
    for(int i = 1; i <= 10001; ++i) if(!vis[i])
    {
        printf("%d
", i - 1);
        return 0;
    }
    return 0;
} 
View Code
原文地址:https://www.cnblogs.com/19992147orz/p/7462599.html