#include<stdio.h>
#define Max 1001
int father[Max];int rank[Max];
void make_set(int x)
{
father[x]=x;
rank[x]=0;
}
int find_set(int x)
{
if(father[x]!=x)
father[x]=find_set(father[x]);
return father[x];
}
int main()
{
int T;int P,Q,a,b,i;
scanf("%d",&T);
while(T--)
{
int count=0;
scanf("%d%d",&P,&Q);
for(i=1;i<=P;i++)
make_set(i);
while(Q--)
{
scanf("%d%d",&a,&b);
rank[a]++;rank[b]++;
a=find_set(a);b=find_set(b);
if(a!=b)
father[a]=father[b];
}
for(i=1;i<=P;i++)
{
if(find_set(i)==i) count++;
if(count>1){
count=-1;break;
}
}
if(count==-1)
printf("No\n");
else{
count=0;
for(i=1;i<=P;i++)
if(rank[i]%2==1) count++;
if(count==0||count==2)
printf("Yes\n");
else
printf("No\n");
}
}
return 0;
附加:判断欧拉图的条件:
1.图是连通的
2.奇节点(领边数为奇数)为2或0
并查集算法模板:
int father[MAX]; /* father[x]表示x的父节点*/
int rank[MAX]; /* rank[x]表示x的秩*/
/* 初始化集合*/
void Make_Set(int x)
{
father[x] = x; //根据实际情况指定的父节点可变化
rank[x] = 0; //根据实际情况初始化秩也有所变化
}
/* 查找x元素所在的集合,回溯时压缩路径*/
int Find_Set(int x)
{
if (x != father[x])
{
father[x] = Find_Set(father[x]); //这个回溯时的压缩路径是精华
}
return father[x];
}
/*
按秩合并x,y所在的集合
下面的那个if else结构不是绝对的,具体<strong>根据实际情况</strong>变化
但是,宗旨是不变的即,按秩合并,实时更新秩。
*/
void Union(int x, int y)
{
x = Find_Set(x);
y = Find_Set(y);
if (x == y) return;
if (rank[x] > rank[y])
{
father[y] = x;
rank[x] += rank[y];
}else
{
if (rank[x] == rank[y])
{
rank[y]++;
}
father[x] = y;
}
}