HDU-1829-A Bug's Life

来源:互联网 发布:网络安全员考试2017 编辑:程序博客网 时间:2024/05/18 15:26


A Bug's Life

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 17337    Accepted Submission(s): 5553


Problem 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
23 31 22 31 34 21 23 4
 

Sample Output
Scenario #1:Suspicious bugs found!Scenario #2:No suspicious bugs found!
Hint
Huge input,scanf is recommended.

HDU-1829-A Bug's Life

思路:

一,将所有的元素当做一个图来搜索,用一个的数组d[]来做标记是否搜索过,以及用于区分同异性,{0,1,2}

0表示未被搜索,1,2用于区分雄雌两个集合。从首遍历一遍,如果有矛盾的则为假。

code 1:

#include<iostream>#include<cstring>using namespace std;const int MAX_N=2005;int T,n,m;bool G[MAX_N][MAX_N];int d[MAX_N];bool DFS(int k);int main(){ios::sync_with_stdio(false);cin>>T;for(int T=1;T<=T;++T){bool boo=true;memset(G,0,sizeof(G));memset(d,0,sizeof(d));cin>>n>>m;int a,b;for(int i=0;i<m;++i){cin>>a>>b;if(a==b)boo=false;G[a][b]=G[b][a]=true;}for(int i=1;i<=n&&boo;++i)if(!d[i]){d[i]=1;if(DFS(i)==false)boo=false;}cout<<"Scenario #"<<T<<":"<<endl;if(boo==true)cout<<"No suspicious bugs found!"<<endl;elsecout<<"Suspicious bugs found!"<<endl;cout<<endl; }return 0;}bool DFS(int k){bool bo=true;int p=(d[k]==1)?2:1;for(int i=1;i<=n&&bo;++i)if(G[k][i]==true){if(!d[i]){d[i]=p;if(DFS(i)==false){bo=false;}}elseif(i!=k&&d[i]!=p)bo=false;}return bo;}


二,并查集,用一个数组存元素的关联元素,将性别相同的放在一个集合里,若关联元素在同一集合则有Bug,否则将性别相同的集合合并。

code 2:

#include<iostream>  #include<algorithm>  using namespace std;const int MAX_N = 10005; /*结点数目上限*/int id[MAX_N];    /*id[x]表示x的父节点*/int Rank[MAX_N];    /*Rank[x]是x的深度的一个上界*/int d[MAX_N];  // 与i性别相反的虫子号int Find(int x);void Union(int x, int y);int main()  { //ios::sync_with_stdio(false);    int T,m,n,k=1;      scanf("%d",&T);    while(T--){        scanf("%d%d",&m,&n);        for(int i=1;i<=m;i++){id[i] = i;  Rank[i]=d[i]=0;        }        int a,b,flag=1;        for(int i=0;i<n;i++){            scanf("%d%d",&a,&b);             if(!flag)continue;            if(Find(a)==Find(b)){  //判断两个虫子在不在同一个集合                  flag=0;continue;            }            if(d[a]==0) d[a]=b;            else Union(d[a],b);            if(d[b]==0) d[b]=a;              else Union(d[b],a);          }        if(flag)    printf("Scenario #%d:\nNo suspicious bugs found!\n",k++);          elseprintf("Scenario #%d:\nSuspicious bugs found!\n",k++);          printf("\n");    }      return 0;  } int Find(int x)  {      if(id[x] != x){        id[x] = Find(id[x]);    }      return id[x];}/*按秩合并x,y所在的集合*/  void Union(int x, int y){    int fx = Find(x);    int fy = Find(y);    if(Rank[fx] > Rank[fy]){/*让Rank比较高的作为父结点*/         id[fy] = fx;    }else{        id[fx] = fy;        if(Rank[fx] == Rank[fy])    Rank[fy]++;    }}

三,带权并查集,用一个集合

struct node{
int k; //父子关系:0 1 
int p; //父亲节点编号 
}id[MAX_N];     

表示元素,其中 k表示父子关系,0表示同性,1表示异性;p为父母编号。

容易推出,儿子 i 与父亲的父亲的关系为 (id[i].k+id[id[i].p].k)%2; 

集合合并时,两集合根节点的关系为 fa=Find(a);id[fa].k=(id[b].k+1+id[a].k)%2;

在处理每对元素时,若他们在同一集合则又他们间的关系为 1(异性),在通过两者与根节点的关系可判断

若(id[a].k+id[b].k)%2==0 则他们间有bug. 若不在同一集合则合并为一个集合。

code 3:

#include<iostream>#include<cstring>using namespace std;const int MAX_N=2005;struct node{int k;//父子关系:0 1 int p;//父亲节点编号 }id[MAX_N];int T,n,m;int Find(int x);void Union(int a,int b);int main(){ios::sync_with_stdio(false);cin>>T;for(int T=1;T<=T;++T){bool boo=true;memset(id,0,sizeof(id));cin>>n>>m;int a,b;for(int i=1;i<=n;++i){id[i].p=i;id[i].k=0;}for(int i=0;i<m;++i){cin>>a>>b;if(boo==false)continue;if(a==b)boo=false;if(Find(a)==Find(b)&&(id[a].k+id[b].k)%2==0){boo=false;}elseUnion(a,b);}cout<<"Scenario #"<<T<<":"<<endl;if(boo==true)cout<<"No suspicious bugs found!"<<endl;elsecout<<"Suspicious bugs found!"<<endl;cout<<endl; }return 0;}int Find(int x){int p=id[x].p;if(id[x].p!=x){id[x].p=Find(id[x].p);id[x].k=(id[x].k+id[p].k)%2;}return id[x].p;}void Union(int a,int b){int fa=Find(a),fb=Find(b);id[fa].p=fb;id[fa].k=(id[b].k+1+id[a].k)%2;}