zoukankan      html  css  js  c++  java
  • 2-臭虫也疯狂(并查集)

    A Bug's Life
    Time Limit: 10000MS   Memory Limit: 65536K
    Total Submissions: 40402   Accepted: 13171

    Description

    Background 
    Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs. 
    Problem 
    Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it.

    Input

    The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one.

    Output

    The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong.

    Sample Input

    2
    3 3
    1 2
    2 3
    1 3
    4 2
    1 2
    3 4

    Sample Output

    Scenario #1:
    Suspicious bugs found!
    
    Scenario #2:
    No suspicious bugs found!

    Hint

    Huge input,scanf is recommended.

    Source

    TUD Programming Contest 2005, Darmstadt, Germany
    方法一:
    224K 719MS
    #include <iostream>
    #include <cstdio>
    using namespace std;
    int father[2005];
    int rea[2005];
    
    int find(int a){         //并查集 
    	int i = a;
    	while(father[i] != i){      
    		i = father[i];
    	}
    	int j = a, r;
    	if(i != j){
    		while(father[j] != i){	//压缩 
    			r = father[j];
    			father[j] = i;
    			j = r;
    		}
    	}
    	return i;
    }
    void mix(int x, int y){      //匹配 
    	int fx = find(x), fy = find(y);
    	if(fx != fy)
    		father[fx] = fy;
    }
    int main(){
    	int t, m, n, a, b;
    	int fa, fb, flag = 1, ct = 0;
    	cin >> t;
    	
    	while(t--){
    		ct++;
    		flag = 1;
    		cin >> m >> n;
    		for(int i = 0; i <= m; i++){
    			father[i] = i;
    			rea[i] = 0;
    		}
    		for(int i = 0; i < n; i++){
    			scanf("%d%d", &a, &b);
    			if(flag){
    				fa = find(a);
    				fb = find(b);
    				if(fa == fb){
    					flag = 0;
    				}
    				else if(rea[fa] && rea[fb]){
    //					father[rea[fa]] = fb;  //这样直接赋值会破坏压缩的树状数组 
    //					father[rea[fb]] = fa;
    					mix(rea[fa], fb);   //不能直接像上面那样直接配对,要查寻到父节点在匹配 
    					mix(rea[fb], fa); 
    				}
    				else if(rea[fa] && rea[fb] == 0){
    //					father[rea[fa]] = fb;
    					rea[fb] = fa;
    					mix(rea[fa], fb);
    				}
    				else if(rea[fa] == 0 && rea[fb]){
    //					father[rea[fb]] = fa;
    					rea[fa] = fb; 
    					mix(rea[fb], fa);
    				}
    				else if(rea[fa] == 0 && rea[fb] == 0){
    					rea[fa] = fb;
    					rea[fb] = fa;
    				}
    			}
    		}
    		if(flag){
    			printf("Scenario #%d:
    ", ct);
    			printf("No suspicious bugs found!
    
    ");
    		}
    		else{
    			printf("Scenario #%d:
    ", ct);
    			printf("Suspicious bugs found!
    
    ");
    		}
    	}
    	return 0; 
    } 
    
    
     
    

      方法二:http://blog.csdn.net/i_want_to_be_a_god/article/details/38379281

    大致题意为:

    给定n个bugs,编号依次1、2、……n。它们之间只有雄性和雌性之分,并给定m对交配的情况,根据这m对交配的情况,判断是否有同性恋出现的情况。若有则输出“No suspicious bugs found!”否则输出“Suspicious bugs found!”;

    题目意思很明确了。而且题型也很清晰,典型的循环路径并查集。分析如下:

    这里令0表示雄性,1表示雌性(这里0和1只不过表示两种对立的状态,并没有具体的含义,可以理解为要么是雄性,要么是雌性)。给每一个bug初始化deep为0,即均为雄性或雌性(深度deep表示bug的相对性别关系)。现在解释一下deep如何表示性别的相对关系:

    假设A匹配B,可令deep[A]=0,deep[B]=1。现在又有B与C匹配,那么deep[B]=1,deep[C]应该为0才对。这样的话,我们可以将具有关系的bug并在同一集合中,并用模2方式来循环表示bug之间的相对性别关系。

    那么假设有匹配A B,这里就有两种情况了。

    1)A与B已经有了关系,即在同一个关系集合中,分两种情况讨论:

      这里deep表示bug之间的相对性别关系,

       11)若A的深度deep与B的深度不同(即一个为0,一个为1),则说明不是同性恋,继续输入关系

       12)若A的深度deep与B的深度相同(即均为0或均为1),则说明是相同性别,为同性恋关系,已可判定结果,后续只需输入关系即可,无需继续判定

    2)A与B还没有关系(即不再同一关系集合中),情况要复杂一些

    由于A与B还没有关系,所以到目前为止是无法断定这个关系是错误的,所以认为这个关系正确(显然)。那么接下来的问题就是:如何将这两个关系和并成一个关系,并且还bug之间的相对性别关系在合并后仍然正确?这就是本题的难点。

    分析如下: 假设A 与 B 匹配,A在以X为父节点的关系中,B在以Y为父节点的关系中。我们可以推到如下:

    deep[A]=a(A与父节点X的相对性别关系为a),由于B与A匹配,那么若将B并在以X为父节点的关系中,则deep[B]=(deep[A]+1)%2。而B在以Y为父节点的关系中的深度为b(即B相对Y的性别关系为b,同样Y相对B的性别关系也为b)。这样若将B并在X关系中,那么Y的深度应该为deep[Y]= ((dee[A]+1)%2+deep[b])%2;这样以后,将Y指向X。我们可以验证一下这样以后是否B与A的相别是相反的即deep[B]=(deep[A]+1)%2;

    上述操作以后:deep[B]=(deep[b]+deep[Y])%2,而deep[Y]= ((dee[A]+1)%2+deep[b])%2,带入后可得deep[B]=(deep[A]+1)%2(容易证明)即关系正确。

    另外本题还要注意一点:最后结果的输出注意首字母要大写,我就贡献了一次WA。

    下面是代码: 180K+719MS

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define Max 2010
    int deep[Max]; //深度关系
    int set[Max]; //并查集
    int Case,n,m;
    int find(int x){ // 查
    	if(set[x]==x) //若循环到父节点,返回父节点标号
    		return x;
    	int temp=find(set[x]); //查找路径上一个节点
    	deep[x]=(deep[set[x]]+deep[x])%2; // 路径更新
    	set[x]=temp; //路径压缩
    	return temp; //返回父节点
    }
    int main(){
        scanf("%d",&Case);
    	for(int i=1;i<=Case;i++){
    		scanf("%d%d",&n,&m);
    		memset(deep,0,sizeof(deep)); //初始化为全0
    		for(int j=1;j<=n;j++) // 初始化为其自身
    			set[j]=j;
    		bool trag=true; //设置标记为没有同性恋
    		int a,b;
    		while(m--){ 
    			if(trag){
    				scanf("%d%d",&a,&b);
    				int x=find(a);
    				int y=find(b);
    				if(x==y){  //若在同一关系集合中
    					if(deep[a]==deep[b]) //若性别相同,则说明是同性恋,否则不是同性恋,正常
    						trag=false; //置标记为false
    				}
    				else{  //不再同一关系集合中,则一定正确,但要正确和并
    					if(x<y){ // 将标号大的并向标号小的
    						deep[y]=((deep[a]+1)%2+deep[b])%2; //改变父节点深度
    						set[y]=x; //大并小
    					}
    					else{ //同上
    						deep[x]=((deep[b]+1)%2+deep[a])%2;
    						set[x]=y;
    					}
    				}
    			}
    			else //若已经判定是同性恋关系,则不予判断,直接输入即可
    				scanf("%d%d",&a,&b);
    		}
    		if(trag) //输出,注意首字母大小写
    			printf("Scenario #%d:
    No suspicious bugs found!
    
    ",i);
    		else
    			printf("Scenario #%d:
    Suspicious bugs found!
    
    ",i);
    	}
    	return 0;
    }									
    

      

     
  • 相关阅读:
    图片验证码, 登录, 注销, 修改密码
    注册页面及注册功能实现
    高级配置文件, csrf, django settings源码, django auth模块, 文件配置的插拔式设计
    cookie操作, session操作, django中间件
    半自动创建多对多关系表, forms组件
    sweetalert, bulk_create, 分页器
    orm查询优化, MVC与MTV, choices参数, ajax
    聚合查询, 分组查询, F与Q查询, 常见字段及参数, 自定义Char字段, 事务操作
    Contest2058
    ACM版《孔乙己》
  • 原文地址:https://www.cnblogs.com/zhumengdexiaobai/p/8370756.html
Copyright © 2011-2022 走看看