Luogu P1525 关押罪犯

传送门

首先 这是一个并查集= =

这道题其实明白了还挺简单的qwq

思路:

因为只看仇恨值最大的一对儿,所以把他们从大到小排序,越大的就尽量分开,直到不能再分为止qwq

  • q[x]表示x最大的敌人(x对q[x]的仇恨值最大);
  • 如果x已经有了最大的敌人q[x],那么y就该跟q[x]分到一起;否则q[x] = y;
  • 所以并查集存的不是两个监狱!存的是“因为有共同敌人而被(勉为其难的)划分到一起的罪犯”;
  • 这几个并查集由于“敌人的敌人”一点点合并到一起;
  • 当目前最大的一对儿敌人已经被分到一个监狱的时候,就说明分不开了,输出。

一些细节:

  • 初始化(fa[i] = i)
  • 判断父亲的时候要用getfather(x)而不是fa[x](因为还没求...)(所以还是先写个xx = getfather(x)吧!)
  • 同样的,合并的时候,用“xx = getfather(x); yy = getfather(y); fa[x] = y;”,
  • 不能写fa[fa[x]]  (fa又不是函数!),也不能写getfather(getfather(x))  (getfather也不是整数!)
  • 结构体p存的是罪犯关系对数,每一个代表a,b的编号和他们的仇恨值c,所以数组大小是1e6(RE了4次qaq) ——“那你为啥开2e5”
  • 如果有冲突的话输出并直接return 0,没有的话循环结束后就输出0!(这个不看题解自己是想不到的qwq)
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 20005;
int fa[maxn],q[maxn];
int n,m;
struct abc {
    int a,b,c;
} p[200005];

int cmp(abc x,abc y) {
    return x.c > y.c;
}

int getfather(int x) {
    if(x == fa[x])return x;
    fa[x] = getfather(fa[x]);
    return fa[x];
}

void add(int x,int y){
    x = getfather(x);
    y = getfather(y);
    fa[x] = y;
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
        fa[i] = i;
    for(int i = 1; i <= m; i++)
        scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
    sort(p+1,p+m+1,cmp);
    for(int i = 1; i <= m; i++) {
        if(getfather(p[i].a) == getfather(p[i].b)){
            printf("%d",p[i].c);
            return 0;
        }
        if(!q[p[i].a])q[p[i].a] = p[i].b;
        else add(q[p[i].a],p[i].b);
        if(!q[p[i].b])q[p[i].b] = p[i].a;
        else add(q[p[i].b],p[i].a);
        
    }
    printf("0");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/mogeko/p/9901944.html