一笔画问题 (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 }
View Code

方法二、并查集

 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 }
View Code

 

posted @ 2013-09-12 18:39  hjf007  阅读(792)  评论(0编辑  收藏  举报