42-一笔画问题
内存限制:64MB 时间限制:3000ms 特判: No
通过数:56 提交数:150 难度:4
题目描述:
zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来。
规定,所有的边都只能画一次,不能重复画。
输入描述:
第一行只有一个正整数N(N<=10)表示测试数据的组数。
每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),分别表示这个画中有多少个顶 点和多少条连线。(点的编号从1到P)
随后的Q行,每行有两个正整数A,B(0<A,B<P),表示编号为A和B的两点之间有连线。
输出描述:
如果存在符合条件的连线,则输出"Yes",
如果不存在符合条件的连线,输出"No"。
样例输入:
2
4 3
1 2
1 3
1 4
4 5
1 2
2 3
1 3
1 4
3 4
样例输出:
No
Yes
欧拉定理:
⒈凡是由偶点组成的连通图,一定可以一笔画成。画时可以把任一偶点为起点,最后一定能以这个点为终点画完此图。
⒉凡是只有两个奇点的连通图(其余都为偶点),一定可以一笔画成。画时必须把一个奇点为起点,另一个奇点终点。
⒊其他情况的图都不能一笔画出。(有偶数个奇点除以二便可算出此图需几笔画成。)
然后使用深搜遍历每个节点。
#include<stdio.h>
#include<string.h>
int book[2000], cnt[2000]; //数组book为记录每个节点是否被用过, cnt数组用来记录节点的度数
int map[2000][2000]; //map用来放图 即邻接矩阵 此问题为无向图
int p, q, a, b;
void dfs(int step)
{
int i;
book[step]=1; //此处节点已被用过
for(i=1; i<=p; i++)
{
if(map[step][i]) // 如果两点间存在连线,则度数加一, 如果没被用过则调用dfs , 即递归
{
cnt[step]++;
if(!book[i])
dfs(i);
}
}
}
int main()
{
int number, i;
scanf("%d", &number);
while(number--)
{
memset(book, 0, sizeof(book)); //数组初始化为零
memset(cnt, 0, sizeof(cnt));
memset(map, 0, sizeof(map));
scanf("%d %d", &p, &q);
for(i=1; i<=q; i++) //创建邻接矩阵, 有连线则为1
{
scanf("%d %d", &a, &b);
map[a][b]=map[b][a]=1;
}
dfs(1); //深搜
int flag=0;
for(i=1; i<=p; i++)
{
if(!book[i]) //如果有没用的点则不能一笔画连成
{
flag=1;
break;
}
}
if(flag)
printf("No\n");
else
{
int count=0; //记录每个奇点
for(i=1; i<=p; i++)
{
if(cnt[i]%2!=0)
count++;
}
if(count==2 || count==0) //奇点数为0 则每个节点都可以作为起点
printf("Yes\n"); //奇点数为2 则两个点一个为起点, 一个为终点
else
printf("No\n");
}
}
return 0;
}