• Luogu P1525 关押罪犯


    Dexription:

    给你m对矛盾关系,每对关系分别涉及到x,y两人,矛盾值为w
    请你判断分配x和y到两个集合中,能否避免冲突
    如能避免请输出0,如果冲突不可避免,请输出最小的矛盾值

    Analysis:

    并查集:
    两个人a,b有仇,那么把他们放在一起显然会打起来,那么我们还不如把a与b的其他敌人放在一起,
    因为这样可能会出现“敌人的敌人就是朋友”的情况,恰好a与b的其他敌人之间没有矛盾,那么他们就可以放在同一个集合中,反之b对a亦然。
    (1)先把所有的矛盾关系按照矛盾值从大到小排一遍序,
    (2)接下来每次操作取出一个关系,看矛盾的两个人x和y是否已经分配到同一个集合中(并查集找父亲即可),那么还分如下两种情况:
    如果在一起那么显然会打起来(会出现矛盾),那么直接输出当前的边权(矛盾值)即可(此时保证是最小矛盾值,因为已经排序了)
    如果不在同一组,则按照“敌人的敌人就是朋友”的原则,把x与y的其他敌人分在同一组,y与x的其他敌人分在同一组

    Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N = 20100,M = 100010;
    struct criminal{
    	int x,y,w;
    }e[M];
    int set[N],enm[N],n,m;
    bool cmp(const criminal &a,const criminal&b) {
    	return a.w > b.w;
    }
    int find(int x)
    {
    	if(set[x] == x) return x;
    	return set[x] = find(set[x]);
    }
    inline void Merge(int x,int y)
    {
    	set[find(y)] = find(x);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i = 1;i <= n;++i) set[i] = i;
    	for(int i = 1;i <= m;++i)
    	{
    		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    	}
    	sort(e+1,e+1+m,cmp);
    	for(int i = 1;i <= m;++i)
    	{
    		int x = find(e[i].x),y = find(e[i].y);
    		if(find(x) == find(y))
    		{
    			printf("%d",e[i].w);
    			return 0;
    		}
    		else{
    			if(!enm[x])
    			{
    				enm[x] = y;
    			}
    			else{
    				Merge(enm[x],y);
    			}
    			
    			if(!enm[y])
    			{
    				enm[y] = x;
    			}
    			else{
    				Merge(enm[y],x);
    			}
    		}
    	}
    	printf("0");
        return 0;
    }
    
    岂能尽如人意,但求无愧我心
  • 相关阅读:
    [匈牙利] 洛谷 P2526 小狗散步
    [匈牙利] 洛谷 P1129 矩阵游戏
    [树形dp] Jzoj P5233 概率博弈
    [线段树] Jzoj P4231 寻找神格
    [状压dp][期望] 洛谷 P2473 奖励关
    [倍增][双向链表] Jzoj P3101 开车旅行
    [高精度][数学] Jzoj P3771 小Z的烦恼
    [并查集][排序] Jzoj P2940 生成输入数据
    [dfs][概率] Jzoj P2941 贿赂
    [权值线段树] Jzoj P4417 神奇的字符串
  • 原文地址:https://www.cnblogs.com/Zforw/p/11348061.html
Copyright © 2020-2023  润新知