[NOIP2010]关押罪犯 计蒜客 - T2099-(扩展域并查集)

总结

都说这个题是扩展域并查集入门题,我也就尝试学了一下,毕竟自己笨,一开始就学难的,脑袋就转不过来了了。

题意

两个囚犯之间有怨气值,如果把他们分在一个监狱就会发生冲突,我们想办法把这些囚犯分到两个监狱,保证最大的冲突怨气值最小。

解析

fat[N<<1],这里我们会开辟两个域,第一个域表示x在监狱1,第二个域表示x在监狱2

我们不断的删除边,从大到小,每删一条就代表x和y一定不在一个监狱。如果x和y已经在同一个监狱了,哪肯定不用删除了,ans就等于这条边的权值。

并查集维护的每棵树。用数据画图的时候,就很明显看出,是一个二分图。每一个监狱连接的其他监狱,一定不在一个监狱。如果这个监狱结点<=n,相邻结点就一定>n。

然后把怨气值从大到小划分,一直划分到在同一个监狱为止

后记

当了我做了食物链那个题后,每个结点维护的存在的所有状态,x在监狱1的状态,x在监狱2的状态
新的关系与之前冲突就结束
不冲突就建立关系

const int N=2e4+5;
const int M=1e5+5;
int fat[N<<1];
struct node
{
    int x,y,v;
    void input(){cin>>x>>y>>v;}
    bool operator<(const node &b)const{return v>b.v;}
}s[M];
int find(int x)
{
    return fat[x]==x?x:fat[x]=find(fat[x]);
}
signed main()
{
    IOS;
    //file();
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n*2;i++)
        fat[i]=i;
    for(int i=0;i<m;i++)
        s[i].input();
    sort(s,s+m);
    int ans=0;
    for(int i=0;i<m;i++)
    {
        int x=find(s[i].x);
        int y=find(s[i].y);
        if(x==y)
        {
            ans=s[i].v;
            break;
        }
        fat[x]=find(s[i].y+n);
        fat[y]=find(s[i].x+n);
    }
    cout<<ans<<endl;
    return 0;
}
发布了130 篇原创文章 · 获赞 5 · 访问量 4992

猜你喜欢

转载自blog.csdn.net/weixin_44224825/article/details/104245795
今日推荐