P1525 关押罪犯(二分图/并查集)

题意:

给你m对矛盾关系,每对关系分别涉及到x,y两人,矛盾值为w

请你判断分配x和y到两个集合中,能否避免冲突

如能避免请输出0,如果冲突不可避免,请输出最小的矛盾值

思路:

方法①:并查集

并查集能维护连通性、传递性,通俗地说,亲戚的亲戚是亲戚

我们不妨这样想:两个人a,b有仇,那么把他们放在一起显然会打起来,那么我们还不如把a与b的其他敌人放在一起,

因为这样可能会出现“敌人的敌人就是朋友”的情况,恰好a与b的其他敌人之间没有矛盾,那么他们就可以放在同一个集合中,反之b对a亦然

我们可以将没对关系按照权值从大到小排序,这样可以保证一旦发生冲突,答案是最小的

对于加入的每段关系,我们先判断他们是否在同一集合内,如果在的话就说明发生冲突,直接输出答案

如果不在一个集合内,我们就将敌人的敌人加入到自己的集合中

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
 using namespace std;
 const int maxn1=2e4+10;
 const int maxn2=1e5+10;
 int fa[maxn1],ene[maxn1];
 struct node{
     int u,v,w;
 }edge[maxn2];
 int find(int x){return fa[x]==x?x:(fa[x]=find(fa[x]));}
 int cmp(node a,node b){return a.w>b.w;}
 int main()
 {
     int n,m;
     scanf("%d%d",&n,&m);
     for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
     for(int i=1;i<=n;i++) fa[i]=i;
     memset(ene,0,sizeof(ene));
     sort(edge+1,edge+1+m,cmp);
     for(int i=1;i<=m;i++){
         int u=edge[i].u,v=edge[i].v,w=edge[i].w;
         int f1=find(u),f2=find(v);
         if(f1==f2){
             cout<<w<<endl;
             return 0;
         }
        else{
            if(!ene[u])    ene[u]=v;
            else    fa[find(ene[u])]=find(v);
            if(!ene[v])    ene[v]=u;
            else    fa[find(ene[v])]=find(u);
        }
     }
    cout<<0<<endl;
    return 0;
 }

方法②:二分图

看到将犯人分成两批应该很容易想到二分图的做法

那么很明显,不是所有所有情况下都能讲犯人分成两部分,必定有一些冲突是无法避免的

我们也可以注意到,冲突是具有单调性的,我们就可以想到二分的做法

我们二分答案,设当前二分的值为mid,此时任意两个矛盾双方x和y必须被分在两个不同集合中,将罪犯们作为节点,在矛盾值大于等于mid的罪犯之间连一条边,我们得到一张无向图。此时我们只需判定这张无向图是否为二分图即可(因为要分为两部分),如果是二分图,令二分右端点R=mid,否则令L=mid即可

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
 using namespace std;
 const int maxn=2e5+10;
 struct edge{
     int u,v,w;
 }p[maxn];
 int n,m,L=0,R=0,cnt=0,head[maxn];
 void add_edge(int x,int y,int w)
 {
     p[++cnt].u=head[x];
     head[x]=cnt;
     p[cnt].v=y;
     p[cnt].w=w;
 }
 bool judge(int mid)
 {
     queue<int> q;
     int color[maxn]={0};
     for(int i=1;i<=n;i++){
         if(!color[i]) color[i]=1,q.push(i);
         while(!q.empty()){
             int x=q.front();
             q.pop();
             for(int j=head[x];j;j=p[j].u){
                 if(p[j].w>=mid){
                     if(!color[p[j].v]){
                         q.push(p[j].v);
                         if(color[x]==1)    color[p[j].v]=2;
                         else    color[p[j].v]=1;
                     }
                    else if(color[p[j].v]==color[x])
                        return false;
                 }
             }
         }
     }
     return true;
 }
 int main()
 {
     scanf("%d%d",&n,&m);
     for(int i=1;i<=m;i++){
         int u,v,w;
         scanf("%d%d%d",&u,&v,&w);
         R=max(R,w);
         add_edge(u,v,w);
         add_edge(v,u,w);
     }
    int ans=0;
    R++;
    while(L+1<R){
        int mid=(L+R)>>1;
        if(judge(mid))    R=mid;
        else L=mid;
    }
    cout<<L<<endl;
    return 0;
  } 

原文地址:https://www.cnblogs.com/overrate-wsj/p/12287872.html

时间: 2024-10-06 00:30:42

P1525 关押罪犯(二分图/并查集)的相关文章

codevs1069关押罪犯(并查集)

题目描述 Description S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极 不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨 气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之 间的积怨越多.如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并 造成影响力为c 的冲突事件. 每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表, 然后上报到S 城Z 市长那

Vijos 1776 关押罪犯 【并查集+贪心】

题目: S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多.如果两名怨气值为c的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c的冲突事件.每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S城Z市长那里.公务繁忙的Z市长只会去看列表中的第一

NOIP2010 关押罪犯 (并查集)

若x,y有关系 将x与y的补集, y与x的补集建立关系 const maxn=20008; maxm=100008; var eg:array[0..maxm,1..3] of longint; f:array[0..maxn*2] of longint; i,j,m,n,x,y,z:longint; procedure swap(var a,b:longint); var c:longint; begin c:=a;a:=b;b:=c; end; function find(x:longint

洛谷P1525 关押罪犯 并查集

无冲突 输出 0 洛谷P1525 关押罪犯 并查集 用拆点法 将一个点拆成两份 一个点和 x 的朋友相连 一个点和 x的敌人相连 若 x 与 y 是敌人 因为只有两个阵营 所以满足敌人的敌人就是朋友 然后 x 连向 y 的敌人 y 连向 x 的敌人 因为这是双向边 所以 y的朋友就是x的敌人就不用连了 如果某一时刻 getfather(e[ i ].from)==getfather(e[ i ].to) 这说明两个点已经是敌人关系的两个人 通过朋友关系连上了 那就结束了 1 #include <

洛谷 P1525 关押罪犯==codevs 1069 关押罪犯[NOIP 2010]

P1525 关押罪犯 513通过 1.4K提交 题目提供者该用户不存在 标签图论并查集NOIp提高组2010 难度普及+/提高 提交该题 讨论 题解 记录 最新讨论 咳咳.竟MLE了. 囧.运行时错误,错误编号-… 点2是何方神圣? 题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多.

做题记录:P1525 关押罪犯(洛谷)

P1525 关押罪犯 /*在这一道题中并查集的作用是:将同一个监狱里的罪犯合并到一起. 思路:将每对罪犯之间的怨气值从大到小排序,再依次把他们分到不 同的两个监狱里,当发现这一对罪犯已经在同一个监狱里时,就说明 他们已经不能再分开了(分开了就不是最优了).此时,这一对罪犯 之间的怨气值就是答案.值得注意的是,当没有冲突发生时,要记得 输出0.那么,我们应该如何用并查集实现以上的思路呢?首先说几个 关键词语的含义: 1."敌人":如果一对罪犯被分到两个不同的监狱里,那么他们就互为&quo

P1525 关押罪犯 并查集

题目链接:https://www.luogu.org/problemnew/show/P1525 一道很难想到思路的题,还可以用二分图染色法,但我们只考虑并查集 要使得冲突最小,首先我们应该让冲突大的尽可能的不在同一个监狱 如果两个相互冲突的人都与第三个人冲突,那么应优先让冲突大的在不同的监狱 那么冲突小的冲突就是不可避免地冲突 如果整个过程都按照冲突的大小从大到小进行的话第一个不可避免的冲突就是将会发生的冲突中最大的一个 用并查集来实现的话,就是将敌人的敌人与自己放在同一个集合中,在同一个集合

洛谷P1525关押罪犯——并查集

题目:https://www.luogu.org/problemnew/show/P1525 并查集+贪心,从大到小排序,将二人分在不同房间,找到第一个不满足的即为答案. 代码如下: #include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,fa[20005],ans,ct,d[20005]; struct N{ int hd,to,w; }edge[1000

洛谷——P1525 关押罪犯

https://www.luogu.org/problem/show?pid=1525 题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多.如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件. 每年年末,警察局会将本年内监狱中的所有冲突事件按