【NOIP2010】关押罪犯

一开始看错题了,然后怎么想都想不明白……
原题:

S 城现有两座监狱,一共关押着 N 名罪犯,编号分别为 1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为 c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并 造成影响力为 c 的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表, 然后上报到 S 城 Z 市长那里。公务繁忙的 Z市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在详细考察了 N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那 么,应如何分配罪犯,才能使 Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

N ≤ 20000,M ≤ 100000。

用并查集做更简单,然而为了我校信仰,我选择二分+二分图

二分一个答案,如果某条边的长度>这个答案说明这个边连接的两个点有冲突,应该放到两边

最开始看成放两个人一个监狱,然后看题解懵逼半天想不明白二分图和两两匹配有啥关系= =

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 int read(){int z=0,mark=1;  char ch=getchar();
 8     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)mark=-1;  ch=getchar();}
 9     while(ch>=‘0‘&&ch<=‘9‘){z=(z<<3)+(z<<1)+ch-‘0‘;  ch=getchar();}
10     return z*mark;
11 }
12 struct ddd{int next,y,value;}e[210000];int LINK[21000],ltop=0;
13 inline void insert(int x,int y,int z){e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;e[ltop].value=z;}
14 int n,m;
15 int maxx=0;
16 int color[21000];
17 bool dfs(int x,int y,int z){
18     if(color[x]!=-1 && color[x]==color[y])
19            return false;
20     if(color[x]==!color[y])  return true;//因为!color[y]只能是0或1,所以这里不用判断color[x]!=-1
21     color[x]=!color[y];
22     for(int i=LINK[x];i;i=e[i].next)if(e[i].value>z)
23         if(e[i].y!=y && !dfs(e[i].y,x,z))  return false;//e[i].y不能是y,防止e[i].y和y之间死循环
24     return true;
25 }
26 bool check(int x){
27     memset(color,-1,sizeof(color));
28     bool can=true;
29     color[0]=0;
30     for(int i=1;i<=n;i++)if(color[i]==-1)
31         if(!dfs(i,0,x)){  can=false;  break;}
32     return can;
33 }
34 int fen(){
35     int fleft=0,fright=maxx,mid;
36     while(fleft+1<fright){
37         mid=(fleft+fright)>>1;
38         if(check(mid))  fright=mid;
39         else  fleft=mid;
40     }
41     return (check(fleft)) ? fleft : fright;
42 }
43 int main(){//freopen("ddd.in","r",stdin);
44     cin>>n>>m;
45     int _left,_right,_value;
46     while(m --> 0){//趋向于
47         _left=read(),_right=read(),_value=read();
48         insert(_left,_right,_value),insert(_right,_left,_value);
49         maxx=max(maxx,_value);
50     }
51     cout<<fen()<<endl;
52     return 0;
53 }

时间: 2024-10-10 07:40:27

【NOIP2010】关押罪犯的相关文章

noip2010(关押罪犯)

4844: Noip2010 关押罪犯 Time Limit: 4 Sec  Memory Limit: 128 MBSubmit: 18  Solved: 12[Submit][Status][Web Board] Description S城现有两座监狱,一共关押着 N名罪犯,编号分别为 1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至 积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值" (一个正整数值)来表示某两名罪犯之间 的仇恨程度,怨气值越大,则这两名罪犯之

noip2010 关押罪犯

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

NOIP2010关押罪犯[并查集|二分答案+二分图]

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

回档|NOIP2010 关押罪犯

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

NOIP2010 关押罪犯(图论+二分)

考试的时候写的最大生成树,然后二分图染色,因为这样两个矛盾很大的罪犯不会被分在一个监狱里面. 然而最大生成树超时,80分. 正解为二分边权,将边权值大于mid的全部连边构图,判断是否为二分图,如果不是二分图,那么无解. 如果无解,则说明边权的限制条件太小了,因为连的边太多,不容易形成二分图:如果有解,则说明边权的限制条件太大,因为更少的边有利于形成二分图. 80分代码,最大生成树: #include<cstdio> #include<cstring> #include<alg

noip2010关押罪犯

题目链接:传送门 题目思路:并查集高级应用(类似食物链那道题),主要是维护两个集合(监狱里犯人的关系),同一个集合里的是朋友,否则是敌人,如果敌人在同一间监狱里, 则最小的最大冲突值求出. #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include &

NOIP2010关押罪犯 二分+二染色

这个题一上来 没有思路,后来想没有思路就二分吧 那么我们来二分 首先,大于当前的mid值的关系,不能出现在一个集合里 (即关系形成的图是一个二分图,判定二分图可以二染色) 如果不能形成二分图,那么说明有些关系要在一个集合里,那就向上二分 否则向下二分 #include<cstdio> #include<cstring> #include<queue> #include<set> #include<cstdlib> #include<algo

[noip2010]关押罪犯 并查集

第一次看的时候想到了并查集,但是不知道怎么实现: 标解,f[i]表示i所属的集合,用f[i+n]表示i所属集合的补集,实现的很巧妙,可以当成一个使用并查集的范例: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<map> 6 #include<ctime> 7 #include<vector>

[NOIP2010]关押罪犯(二分+二分图染色)

传送门 大意:我们把图分为两部分,使得两部分中的内部边的最大权值最小. 思路:哎,拿到题的时候想了二分图染色,发现不好做,但我没有想到二分,只好最后去骗了一个30分.正确的思路是:首先我们要 去二分最大的冲突边的是哪一条(按照权值二分),因为当二分的边权增大时,连的边也就越少,连通块的数目就越多,冲突就越少,所以边权是可以二分的,在二分过后用二分图判定,如果可以染成二分图即为可行的解. 代码: #include<cstdio> #include<algorithm> #includ

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