Noip2010 关押罪犯

SOl1:开虚点的方法

并查集的精义在于物以类聚,信息的传递性。

即A认识B,B认识C,则A认识C。

对于本题1与2有冲突,那我们自然要将它们分开才行。

如果1又与3冲突,那3自然要与2放在一个房间了。至于是放哪个房间,不是重点。

发现每个人与其它人的关系,只有两种即有冲突,没有冲突。

于是我们可以对每个人开两个集合出来,一个集合放与之没有冲突的,另一个集合放与之有冲突的。

这样便引出的虚点的概念来了。

于是1开出1号点,与1+N号点,2开出2号点,与2+N号点。

接下来1与2有冲突,于是1与N+2号点放一个集合,2与N+1号点放一个集合。这样就完整的表述了1与2有冲突这个事情。

于是这样一直放下去,直到当发现发生某个冲突的两个人,居然在一起集合里面(在一个集合说明它们是和平相处的),则说明这个冲突是无法避免的了。

/*
此题还可以用二分答案加二分图染色的方法来做
二分答案是指二分一下,前多少条冲突规则是可以接受的
二分图染色是说,对于一个图,我们将一个点染成黑色,则这条边的
另一个点染成白色。反之亦然,如果染好一个点后,发现与之相连的
另一个点染的色,居然与之相同,则染色失败
*/ 

#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int x,y,z;
}e[200020]; 
int tot,s,n,m;
int head[20005],b[20005],a[100005];
bool f;
int cmp(int a,int b){return a<b;}
void insert(int x,int y,int z)
{
    e[++tot].x=y;
    e[tot].y=z;
    e[tot].z=head[x];
    head[x]=tot;
}
void dfs(int x,int data)
{
    if(f==false)  //如果已染色失败,则退出 
	   return;
    b[x]=data;//将x这个点染成data色 
    for(int i=head[x];i!=0;i=e[i].z) //遍历所有与x相连的边 
    {
        if(e[i].y>s) 
		//注意这一句,并不是所有的边都要走的
		//这也是前面为什么要记下每条边冲突值的原因 
        {
            if(b[e[i].x]==-1) //如果这个点没有被染色 
			    dfs(e[i].x,1-data); //染成另一种颜色 
            else
            if(b[e[i].x]==data) //如果已被染了,且与当前点一样,则染色失败 
			  {
			     f=false;
				 return;
			  }
        }
    }
}
bool work(int midd)
{
    memset(b,-1,sizeof(b));
    f=true;//假设能染色成功 
    s=a[midd];//记下第midd条冲突的怨气值 
    for(int i=1;i<=n;i++)
        if(b[i]==-1)  
		//注意前midd条规则所产生的,可能是一个森林,
		//于是当发现一个点没有被染色,就对它进行染色 
		    dfs(i,0);
    return f;
}
int main()
{
    cin>>n>>m;
    memset(head,0,sizeof(head));
    int x,y,z;
    tot=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        insert(x,y,z);
        insert(y,x,z);
        a[i+1]=z; //记下这条边的冲突值,在后面有用到的 
    }
    a[1]=0; //有可能所有冲突都可以避免,所以要有边权的0的。
    sort(a,a+m+1,cmp);//对冲突值进行升序排列 
    int l=1,r=m+1,mid;
    while(l<r) //二分答案,二分一个冲突编号出来,以它的冲突值为最小值,将值大于它的边进行构图。
    {
        mid=(l+r)/2;
        if(work(mid)==true) //染色成功,说明冲突值还可以于变小一点,于是右边界移动。
		    r=mid;
        else 
		     l=mid+1;
    }
    cout<<a[l];
}

  
原文地址:https://www.cnblogs.com/cutemush/p/12410731.html