zoukankan      html  css  js  c++  java
  • 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];
    }
    
      
    
  • 相关阅读:
    阿里的面试官都喜欢问哪些问题?
    Spring AOP中的JDK和CGLib动态代理哪个效率更高?
    招聘季!送你21套经典面试题!助你一臂之力!
    Spring AOP中的JDK和CGLib动态代理哪个效率更高?
    为什么需要分布式配置中心?
    线上出故障了!我慌得一匹!教大家如何应对在线故障!
    阿里巴巴的26款超神Java开源项目!
    完了!生产事故!几百万消息在消息队列里积压了几个小时!
    十大经典排序算法(动图演示)
    用户画像学习笔记
  • 原文地址:https://www.cnblogs.com/cutemush/p/12410731.html
Copyright © 2011-2022 走看看