noip提高组2010关押罪犯(luogu p1525)

原题链接:https://www.luogu.org/problem/show?pid=1525

并查集的补集问题。

首先将所有的事件按影响力从大到小排序,依次试图避免这些事件。

建立一个2*n的并查集,用来代表两个监狱。

如果涉及当前事件的两个罪犯已经在前面的处理中被分配在同一个监狱中,那么这个冲突就无法被避免,否则将任意一个罪犯移至另一监狱,将会产生影响力更大的冲突事件。

否则秉承着“敌人的敌人就是朋友”的原则,将两个罪犯放在不同的监狱,合并并查集即可。

此题还有二分图做法,诸位可以自行研究。

#include<cstdio>
#include<algorithm>
using namespace std;
void read(int &y)
{
    y=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9')
    {
        y=y*10+x-'0';
        x=getchar();
    }
}
struct g
{
    int a,b,c;
}p[100005];
bool cmp(g x,g y)
{
    return x.c>y.c;
}
int n,m,f[40005];
int find(int x)
{
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=2*n;++i) f[i]=i;
    for(int i=1;i<=m;++i)
    {
        read(p[i].a);read(p[i].b);read(p[i].c);
    }
    sort(p+1,p+m+1,cmp);
    for(int i=1;i<=m;++i)
    {
        int x=find(p[i].a),y=find(p[i].b);
        if(x==y)
        {
            printf("%d",p[i].c);
            return 0;
        }
        f[x]=find(p[i].b+n);
        f[y]=find(p[i].a+n);
    }
    printf("0");
    return 0;
}
原文地址:https://www.cnblogs.com/zeroform/p/7608621.html