Problem地址:http://acm.hdu.edu.cn/showproblem.php?pid=1829
看完这题,我想到了用并查集。
我用gender[]表示相应编号的小虫的性别--boy / girl
对每只输入的小虫预设性别
如输入 1 2
3 4 ( 图中B代表boy,G代表girl )
继续输入 1 3时,会发现1 3性别相同,但此时还不能判断错误,因为如果将右边这棵树的所有虫子性别更改后及又可满足条件
然后将两树合并
之后怎么判断题中推论是否正确呢?
可以这样:当输入的数据在同一棵树,但两只小虫性别却相同,即可判断错误,如继续输入2 3时。否则一直认为题中推论一直是正确的。
因为输入数据很多,可能会有重复输入,所以有必要采取点措施避免重复输入带来的影响。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int boy = 1;
const int girl = -1;
const int maxn = 2000 + 50;
int gender[maxn];
int used[maxn];
bool vis[maxn][maxn];
inline void change ( int &a, int &b ) //交换a,b值,但这可能或许是多此一举
{
if( a > b )
{
a = a+b;
b = a-b;
a = a-b;
}
}
int find( int n )
{
if( n!=used[n] )
used[n] = find( used[n] );
return used[n];
}
void repair( int N, int tar ) //修改一棵树上所有小虫的性别
{
int i;
for( i=1;i<=N;i++ )
if( used[i]==tar )
gender[i] = - gender[i];
}
int main()
{
int T;
int N, M;
int i, j;
bool assum; //判断推论是否正确
int t1, t2;
int x, y;
int c=0;
cin>>T;
while( T-- )
{
scanf( "%d%d", &N, &M );
memset(vis,false,sizeof(vis));
memset(gender,0,sizeof(gender));
for( i=1;i<=N;i++ )
used[i] = i;
assum=true; //初始化
for( i=0;i<M;i++ )
{
if( assum )
{
scanf( "%d%d", &t1, &t2 );
if( vis[t1][t2] ) //判断是否为重复输入
continue;
change( t1,t2 );
if( !gender[t1] && !gender[t2] )
{
gender[t1] = boy;
gender[t2] = girl;
used[t2] = t1;
}
else if( !gender[t2] && gender[t1] )
{
x=find(t1);
gender[t2] = -gender[t1];
change( x, t2 );
used[t2] = x;
}
else if( !gender[t1] && gender[t2] )
{
x=find(t2);
gender[t1] = -gender[t2];
change( x, t1 );
used[t1] = x;
}
else if( gender[t1] && gender[t2] )
{
x = find(t1);
y = find(t2);
if( x==y && gender[t1]==gender[t2] )
assum = false;
else if( x!=y && gender[t1]!=gender[t2] )
{
change(x,y);
used[y] = x;
}
else if( x!=y && gender[t1]==gender[t2] )
{
change(x,y);
repair(N,x);
used[y] = x;
}
}
vis[t1][t2] = vis[t2][t1] = true; //标记输入
}
else //已经有反例说明题中推论错误,就不必继续判断了
scanf( "%d%d", &t1, &t2 );
}
c++;
printf("Scenario #%d:\n",c);
if( assum )
printf("No suspicious bugs found!\n\n");
else
printf("Suspicious bugs found!\n\n");
}
return 0;
}