洛谷题单指南-集合-P1525 [NOIP2010 提高组] 关押罪犯

原题链接:https://www.luogu.com.cn/problem/P1525

题意解读:有很多罪犯,要关到两座监狱,有一些罪犯之间有仇,并且可以量化出仇恨值,如果关在一起就会冲突,造成的影响就是仇恨值,要使得造成的影响最小,如果可以完全不起冲突,输出0。

解题思路:

首先,要让冲突影响最小化,显然应该把仇恨大的罪犯分开。

将所有罪犯关系、仇恨值按仇恨值大小降序排序

遍历每一对罪犯,判断他们是否已经在同一个集合(监狱)

如果已经属于同一个集合,则输出他们的仇恨值,即为答案。

如果不属于同一个集合,就要将两人分到两个集合(监狱),问题的关键来了,如何分配罪犯?

初始时,如果两人之前都没有仇人,则不着急合并,记录下两人为各自的仇人

接下来,如果两人能找到各自仇人,则将其与对方的仇人放在一个集合。(解释:a、b两人,a如果已经有仇人了,说明a和仇人的仇恨值更大,因为是在前面遍历到,a显然不能和其仇人分到一个集合,应该将b跟a的仇人分到一个集合,同样,a应该跟b的仇人分到一个集合)

100分代码:

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

const int N = 20005, M = 100005;

int p[N]; //并查集,罪犯所属的集合

//查找x所在集合
int find(int x)
{
    if(p[x] == x) return p[x];
    return p[x] = find(p[x]);
}
//将x、y合并
void merge(int x, int y)
{
    p[find(x)] = find(y);
}

struct node
{
    int a, b, c; //a 和 b的怨气值c
} s[M];

bool cmp(node x, node y)
{
    return x.c >= y.c;
}

int enemy[N]; //存储已出现的每个人的敌人-存在仇恨值的人
int n, m;

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= m; i++)
    {
        cin >> s[i].a >> s[i].b >> s[i].c;
    }

    for(int i = 1; i <= n; i++) p[i] = i;
    sort(s + 1, s + m + 1, cmp); //按仇恨值降序排序
    bool nowar = true; //是否没有任何冲突
    for(int i = 1; i <= m; i++)
    {
        int u = s[i].a, v = s[i].b;
        if(find(u) == find(v)) //如果两个人已经属于同一个集合,则无法再划分,此时的仇恨值即答案
        {
            cout << s[i].c;
            nowar = false; //说明会产生冲突
            break;
        }
        else
        {
            if(!enemy[u]) enemy[u] = v; //如果u没有敌人,给u设置敌人v
            else merge(enemy[u], v); //如果u有敌人,把v和u的敌人分到一个集合
            if(!enemy[v]) enemy[v] = u; //如果v没有敌人,给v设置敌人u
            else merge(enemy[v], u); //如果v有敌人,把u和v的敌人分到一个集合
        }
    }    
    if(nowar) cout << 0; //如果没有任何冲突,输出0

    return 0;
}

 

posted @ 2024-03-22 21:04  五月江城  阅读(23)  评论(0编辑  收藏  举报