一笔画问题 (DFS或并查集)
题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=42
一笔画问题是欧拉回路的一个变形,可以一笔画的条件有两个:1、所有顶点必须连通 2、度数为奇数的点有0个或2个,若有两个必然一个是起点,一个是终点。
考虑用dfs遍历图,判断是否连通, 结合度数的特点,判断即可。
当然本题我的代码用时28MS,但是这个0MS通过的人非常多,可以采用并查集的方法,我的并查集代码用时4MS,看来还是有待提高啊……
方法一、DFS
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 int map[1005][1005]; 5 int flag[1005]; 6 int p[1005]; 7 int n,m; 8 9 void dfs(int x) //dfs判断图的连通性 10 { 11 int i; 12 flag[x]=1; 13 for(i=1;i<=n;i++) 14 if(!flag[i]&&map[x][i]&&i!=x) //i点未被访问且有边且不等于起点 15 dfs(i); 16 } 17 18 int main() 19 { 20 int T,u,v,i,ok,count; 21 scanf("%d",&T); 22 while(T--) 23 { 24 ok=1; 25 count=0; 26 memset(map,0,sizeof(map)); 27 memset(flag,0,sizeof(flag)); 28 memset(p,0,sizeof(p)); //p存储度数 29 scanf("%d%d",&n,&m); 30 for(i=1;i<=m;i++) 31 { 32 scanf("%d%d",&u,&v); 33 map[v][u]=1; 34 map[u][v]=1; 35 ++p[v]; 36 ++p[u]; 37 } 38 dfs(1); 39 for(i=1;i<=n;i++) 40 { 41 if(!flag[i]) {ok=0;break;} 42 if(p[i]&1) count++; //度数为奇数的数记录下个数 43 } 44 if(ok) 45 { 46 if(count==0||count==2) printf("Yes\n"); 47 else printf("No\n"); 48 } 49 else 50 printf("No\n"); 51 } 52 return 0; 53 }
方法二、并查集
1 #include<stdio.h> 2 #include<string.h> 3 int fa[1005],p[1005]; 4 5 int findset(int x) {return fa[x]!=x ? fa[x]=findset(fa[x]) : x ; } //并查集优化代码 6 7 int main() 8 { 9 int T,n,m,x,y,i,sum,count; 10 scanf("%d",&T); 11 while(T--) 12 { 13 memset(p,0,sizeof(p)); //p存储度数 14 count=0; sum=0; 15 for(i=0;i<=1005;i++) fa[i]=i; 16 scanf("%d%d",&n,&m); 17 for(i=0;i<m;i++) 18 { 19 scanf("%d%d",&x,&y); 20 p[x]++; 21 p[y]++; 22 x=findset(x); 23 y=findset(y); 24 if(x!=y) fa[x]=y; //若不在同一个集合中,合并集合 25 } 26 for(i=1;i<=n;i++) 27 if(fa[i]==i) count++; //父节点为他本身的点的个数,连通情况下只有一个,就是起点 28 for(i=1;i<=n;i++) 29 { 30 if(p[i]&1) //sum为顶点度数为奇数的个数 31 sum++; 32 } 33 if((count==1)&&(sum==0||sum==2)) 34 printf("Yes\n"); 35 else printf("No\n"); 36 } 37 return 0; 38 }