3 3 1 2 1 3 2 3 3 2 1 2 2 3 0
1 0
这里先口述一下什么是欧拉道路:一笔连接所有点构成的道路.(不成环).
即,一笔连接所有点构成的环,就可以叫做欧拉回路。
我们知道 并查集的操作可以轻松搞定连接两个点的操作.所以这里用并查集来解这个题:
下边是连接两个点的操作
void merge(int a,int b) { int A,B; A=find(a); B=find(b); if(A!=B) f[B]=A; }
int find(int a) { int r=a; while(f[r]!=r) r=f[r]; int i=a; int j; while(i!=r) { j=f[i]; f[i]=r; i=j; } return r; }
然后介绍解题关键的数组
int f[12121212];//并查集数组 int path[121212];//判断点出现次数的数组
解题思路:
我们知道 如下例子能够构成一个回路(有且只有一个回路)
1 2
2 3
1 3
这个时候我们知道每个点的出现次数为2
这里再给出一个反例:
1 2
2 3
这个例子 2 出现了两次 而1 3 没有出现两次 (没有构成回路)
这里再给出一个反例:
1 4
1 2
2 4
1 3
2 3
这个例子里边只有4出现了两次 其他的出现多次(构成了多个回路)
读者这里可以自行多取几个例子进行证明
由此可以见得:只有每个节点都出现了两次的时候才是构成了一个回路(有且仅有一个~)
这个时候我们每读入一组数据的时候就要对节点出现的次数进行统计 并且进行节点的链接,
最终判断是否成环的时候就要涉及到并查集的操作了:链接节点.
当所有读入的数据的节点都链接成功了之后 并查集数组会指向唯一的一个节点.
这个时候就有了如下的判断:
int huan=0; int tongji=0; for(int i=0;i<n;i++) { if(f[i]==i){huan++;if(huan>1)break;} if(path[i]!=2)tongji++; } if(huan>1) { printf("0\n"); continue; } if(tongji==0) printf("1\n"); else printf("0\n");
然后这里贴上完整的AC代码:
#include<stdio.h> #include<string.h> using namespace std; int f[12121212]; int path[121212]; int n,m; void init() { for(int i=0;i<n;i++) f[i]=i; } int find(int a) { int r=a; while(f[r]!=r) r=f[r]; /*int i=a; int j; while(i!=r) { j=f[i]; f[i]=r; i=j; }*/ return r; } void merge(int a,int b) { int A,B; A=find(a); B=find(b); if(A!=B) f[B]=A; } int main() { while(~scanf("%d",&n)) { if(n==0)break; scanf("%d",&m); init(); memset(path,0,sizeof(path)); while(m--) { int x,y; scanf("%d%d",&x,&y); x--; y--; merge(x,y); path[x]++; path[y]++; } int huan=0; int tongji=0; for(int i=0;i<n;i++) { if(f[i]==i){huan++;if(huan>1)break;} if(path[i]!=2)tongji++; } if(huan>1) { printf("0\n"); continue; } if(tongji==0) printf("1\n"); else printf("0\n"); } }