题解【luoguP1525 NOIp提高组2010 关押罪犯】

题目链接


题解

算法

  • 一个经典的并查集
  • 但是需要用一点贪心的思想

做法

  • 先将给的冲突们按冲突值从大到小进行排序(这很显然)
  • 然后一个一个的遍历它们
  • 如果发现其中的一个冲突里的两个人在同一个集合里,直接输出当时的冲突值
  • 否则,第一个人不妨设其为 x x ,用一个 op[x] o p [ x ] 来保存上一个与他冲突的人。如果 op[x] o p [ x ] 0 0 ,也就是还没有上一个冲突,直接将 op[x] o p [ x ] 赋值为当时的第二个人(不妨设其为 y y );如果有冲突,则直接将 op[x] o p [ x ] y y 合并。

代码

#include 
#include 
#include 
#define MAXN 20005
#define MAXM 100005
using namespace std;

int n, m;
int p[MAXN];
int op[MAXN];//保存冲突 
int ans;
struct fight
{
    int x, y;
    int s;
}l[MAXM];

bool cmp(fight t1, fight t2)
{
    return t1.s > t2.s;
}//结构体排序 

int find(int x)
{
    if(p[x] < 0) return x;
    return p[x] = find(p[x]); 
}//路径压缩 

void Union(int x, int y)
{
    x = find(x);
    y = find(y);
    if(x == y) return ;
    if(p[x] > p[y]) swap(x, y);
    p[x] += p[y];
    p[y] = x;
}//合并 
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) p[i] = -1;
    for(int i = 1; i <= m; i++) scanf("%d%d%d", &l[i].x, &l[i].y, &l[i].s);
    sort(l + 1, l + m + 1, cmp);
    for(int i = 1; i <= m; i++)
    {
        int a = l[i].x;
        int b = l[i].y;
        int fa = find(a);
        int fb = find(b);
        if(fa == fb)
        {
            ans = l[i].s;
            break;
        }
        else
        {
            if(op[a] == 0) op[a] = b; //如果没有冲突,将冲突设置为b 
            else Union(find(b), find(op[a]));//有冲突,合并 

            if(op[b] == 0) op[b] = a;
            else Union(find(a), find(op[b]));//同上

            //主思路 
        }
    }
    printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(题解,NOIP提高组)