Codevs 1069 关押罪犯 2010年NOIP全国联赛提高组

时间:2022-03-04 20:42:39

1069 关押罪犯 2010年NOIP全国联赛提高组

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 钻石 Diamond

题目描述 Description

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

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

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

输入描述 Input Description

第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨气值为cj。数据保证,且每对罪犯组合只出现一次。

输出描述 Output Description

共1 行,为Z 市长看到的那个冲突事件的影响力。如果本年内*

中未发生任何冲突事件,请输出0。

样例输入 Sample Input

4 6

1 4 2534

2 3 3512

1 2 28351

1 3 6618

2 4 1805

3 4 12884

样例输出 Sample Output

3512

数据范围及提示 Data Size & Hint

罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件

影响力是3512(由2 号和3 号罪犯引发)。其他任何分法都不会比这个分法更优。

【数据范围】

对于30%的数据有N≤ 15。

对于70%的数据有N≤ 2000,M≤ 50000。

对于100%的数据有N≤ 20000,M≤ 100000。

分类标签 Tags

二分法 并查集 树结构 大陆地区 NOIP全国联赛提高组 2010年

/*
带权并查集.
贪心策略+并查集维护.
并查集维护两个人是不是敌人.
当扫到两个人x,y时.
维护father[find(x+n)]=find(y).
把y的朋友归为自己的敌人.
x维护同理.
*/
#include<cstdio>
#include<algorithm>
#define MAXN 100001
using namespace std;
int father[MAXN],n,m;
struct data{int x,y,z;}s[MAXN];
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*f;
}
bool cmp(const data &x,const data &y)
{
return x.z>y.z;
}
int find(int x)
{
return x!=father[x]?father[x]=find(father[x]):x;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=2*n;i++) father[i]=i;
for(int i=1;i<=m;i++)
s[i].x=read(),s[i].y=read(),s[i].z=read();
sort(s+1,s+m+1,cmp);
for(int i=1;i<=m;i++)
{
int l1=find(s[i].x),l2=find(s[i].y);
if(l1==l2)
{
printf("%d",s[i].z);return 0;
}
father[find(s[i].x+n)]=l2,father[find(s[i].y+n)]=l1;
}
printf("0");
return 0;
}
/*
二分+二部图染色.
把两个*看成两个集合.
那么这就成了一个二部图相关的问题.
我们认为有仇恨关系的不能在一个集合里.
但是我们可能不能完全避免矛盾.
我们把不同颜色作为集合的flag.
那么有仇恨关系的不能在一个集合里.
我们二分一个仇恨值,单调性显然.
我们把大于仇恨值的罪犯染色.
看能不能染出整张图.
*/
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#define MAXN 100001
using namespace std;
int father[MAXN],n,m,s[MAXN],max1,mid,head[MAXN],tot,ans;
int b[MAXN];
struct data{int v,next,x;}e[MAXN*2];
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*f;
}
void add(int u,int v,int z)
{
e[++tot].v=v;
e[tot].x=z;
e[tot].next=head[u];
head[u]=tot;
}
bool dfs(int u)
{
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(e[i].x>mid)
{
if(b[u]==b[v]) return false;
if(!b[v])
{
b[v]=3-b[u];
if(!dfs(v)) return false;
}
}
}
return true;
}
bool check(int x)
{
for(int i=1;i<=n;i++)
{
if(!b[i])
{
b[i]=1;
if(!dfs(i)) return false;
}
}
return true;
}
void erfen(int ll,int rr)
{
while(ll<=rr)
{
memset(b,0,sizeof(b));
mid=(ll+rr)>>1;
if(check(mid)) ans=mid,rr=mid-1;
else ll=mid+1;
}
}
int main()
{
int x,y,z;
n=read(),m=read();
for(int i=1;i<=m;i++)
{
x=read(),y=read(),z=read();
max1=max(max1,z);add(x,y,z);add(y,x,z);
}
erfen(0,max1);
printf("%d",ans);
return 0;
}