一笔画问题
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
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
来源
- [张云聪]原创 上传者
-
第一行只有一个正整数N(N<=10)表示测试数据的组数。
思路:题意,主要判断图是否为欧拉通路或则为欧拉回路,而欧拉通路或欧拉回路有以下特点:
(1)无孤立顶点;
(2)每个顶点度数都为偶数或则有两个奇数顶点。
(3)如果有两个奇数顶点,则从奇度顶点开始深搜,才能走完所有的边。
具体的代码中有注释。
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>G[1100];
int n,m,vis[1100],k; //vis数组存的是顶点的度
int book[1100][1100]; //book数组用来标记走过的边
void dfs(int x)
{ //k表示经过的顶点个数,
k++;
if(k>=m+1)
return ;
for(int i=0; i<G[x].size(); i++)
{
int s=G[x][i];
if(!book[x][s]) //标记
{
book[x][s]=1;
book[s][x]=1;
if(k>=m+1)
return ;
dfs(s);
}
}
return ;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(vis,0,sizeof(vis));
memset(book,0,sizeof(book));
scanf("%d %d",&n,&m);
int i , j=1 , x , y,flag=0;
for(i=1; i<=n; i++)
G[i].clear();
for(i=0; i<m; i++)
{
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
vis[x]++;
vis[y]++;
}
k=0;
for(i=1; i<=n; i++)
{
if(vis[i]==0) //vis 如果为0,则表示孤立点,不可能一边画下来
flag=1;
else if(vis[i]%2) //k表示奇数顶点的个数
{
k++;
j=i; //j表示顶点的下标。
}
}
if(flag)
{
printf("NO\n");
continue;
}
if(k==0||k==2) //如果要形成欧拉回路或者欧拉通路。则奇度顶点的个数为0或则为2;
{
k=0;
dfs(j);
if(k==m+1)
{
printf("Yes\n");
}
else printf("No\n");
}
else printf("No\n");
}
return 0;
}