关押罪犯 并查集+二分

来源:互联网 发布:井柏然毁了肖奈 知乎 编辑:程序博客网 时间:2024/06/06 12:33

题目描述

S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?


A、并查集

把边按权值从大到小排序,再顺次将各个边上的两点x,y并查集所在的子树合并,当有冲突时,当前边的权就是所求。(类似于POJ2492 A Bug's Life)。

代码:

#include<cstdio>#include<iostream>#include<vector>#include<algorithm>using namespace std;int n,m;struct Edge {int x,y,z;Edge() {}Edge(int xx,int yy,int zz) {x=xx,y=yy,z=zz;}};vector<Edge> a;int fa[20005]= {0};bool k[20005]= {0};int find(int x) {if(fa[x]==0) {return x;}int y=find(fa[x]);k[x]=k[x]^k[fa[x]];return fa[x]=y;}bool my_cmp(Edge x,Edge y) {if(x.z>y.z) {return true;}return false;}int main() {scanf("%d%d",&n,&m);for(int i=1; i<=m; i++) {int x,y,z;scanf("%d%d%d",&x,&y,&z);a.push_back(Edge(x,y,z));}sort(a.begin(),a.end(),my_cmp);bool flag=true;for(int i=0; i<a.size(); i++) {int rootx=find(a[i].x),rooty=find(a[i].y);if(rootx==rooty&&k[a[i].x]==k[a[i].y]) {printf("%d",a[i].z);flag=false;break;}if(rootx!=rooty) {if(k[a[i].x]==k[a[i].y]) {k[rooty]=k[rooty]^1;}fa[rooty]=rootx;}}if(flag==true) printf("0");return 0;}

B、二分

二分可能的答案。判断答案是否可行时,就相当于判断去掉边权比当前答案x小的边后的图是否是二分图,用二分图染色判断就可以了。

#include<cstdio>#include<iostream>#include<vector>#include<cstring>using namespace std;int n,m;struct Edge {int y,z;Edge() {}Edge(int yy,int zz) {y=yy,z=zz;}};vector<Edge> a[20005];int color[20005]= {0};bool dfs(int x,int fa,int num) {color[x]=3-color[fa];for(int i=0; i<a[x].size(); i++) {if(a[x][i].z<=num) continue;if(color[a[x][i].y]!=0) {if(color[a[x][i].y]==color[x]) {return false;}continue;}if(dfs(a[x][i].y,x,num)==false) {return false;}}return true;}int main() {scanf("%d%d",&n,&m);int biggest=0;for(int i=1; i<=m; i++) {int x,y,z;scanf("%d%d%d",&x,&y,&z);a[x].push_back(Edge(y,z));a[y].push_back(Edge(x,z));biggest=max(biggest,z);}int left=0,right=biggest,middle;while(right>left+1) {memset(color,0,sizeof(color));color[0]=2;middle=(left+right)/2;for(int i=1; i<=n; i++) {if(color[i]==0) {if(dfs(i,0,middle)==false) {left=middle;break;}}}if(left!=middle) {right=middle;}}if(left==0&&right==1) printf("0");else printf("%d",right);return 0;}


注意,此题答案为0时要单独判断。


0 0
原创粉丝点击