返回顶部

AcWing - 257 - 关押罪犯 = 并查集

https://www.acwing.com/problem/content/259/

这道题蛮有趣的。

思路之一,是边带权并查集,相当于给点黑白染色,经过一条边权为1的边则改变一次颜色,规定到根节点边权和为0的为黑色。这样做的时候需要注意,合并两个不同并查集的x,y的时候,需要注意现在的黑白色只是当前连通块以内的颜色,当某次操作需要把两个不同连通块之间的黑色连在一起,则边权要带1,使子树的颜色全部翻转。

更简单的思路是,为每个人维护一个“对方集合”代表元素,每次把x,y合并的时候,假如x的“对方集合”为空则把y作为“对方集合”的第一个元素,否则把y和x的“对方集合”合并。假如某次要合并的x,y本身就在同一个集合中,直接false。

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

int fa[20005];
bool d[20005];

int find(int x) {
    if(x == fa[x])
        return x;
    int rt = find(fa[x]);
    d[x] ^= d[fa[x]];
    return fa[x] = rt;
}

void merge(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if(d[x] == d[y])
        d[fx] ^= 1;
    fa[fx] = fy;
}

bool check(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if(fx == fy) {
        if(d[x] == d[y])
            return false;
        return true;
    }
    merge(x, y);
    return true;
}

struct Edge {
    int u, v, w;
    bool operator<(const Edge &e)const {
        return w > e.w;
    }
} edge[100005];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        fa[i] = i;
        d[i] = 0;
    }
    int m;
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i) {
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
    }
    sort(edge + 1, edge + 1 + m);
    bool put = 0;
    for(int i = 1; i <= m; ++i) {
        if(check(edge[i].u, edge[i].v)) {
            //printf("%d %d %d\n", edge[i].u, edge[i].v, edge[i].w);
        } else {
            put = 1;
            printf("%d\n", edge[i].w);
            break;
        }
    }
    if(!put)
        puts("0");
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int fa[20005];
int enemy[20005];

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

void merge(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fa[fx] = fy;
}

bool check(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    if(fx == fy)
        return false;
    else {
        if(enemy[fx] == 0)
            enemy[fx] = fy;
        else
            merge(enemy[fx], fy);
        if(enemy[fy] == 0)
            enemy[fy] = fx;
        else
            merge(enemy[fy], fx);
        return true;
    }
}

struct Edge {
    int u, v, w;
    bool operator<(const Edge &e)const {
        return w > e.w;
    }
} edge[100005];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        fa[i] = i;
        enemy[i] = 0;
    }
    int m;
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i) {
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
    }
    sort(edge + 1, edge + 1 + m);
    bool put = 0;
    for(int i = 1; i <= m; ++i) {
        if(check(edge[i].u, edge[i].v)) {
            //printf("%d %d %d\n", edge[i].u, edge[i].v, edge[i].w);
        } else {
            put = 1;
            printf("%d\n", edge[i].w);
            break;
        }
    }
    if(!put)
        puts("0");
}
posted @ 2019-08-28 14:11  Inko  阅读(182)  评论(0编辑  收藏  举报