一笔画问题
时间限制:
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)表示测试数据的组数。
一笔画问题是一个运用搜索和欧拉回路才能做出来的题目,如果光用搜索能 做出来,但是会远远的超时,所以不能单单使用搜索来做,其实搜索很多题目都是 要通过剪枝来避免超时的,欧拉回路就是专门解决一笔画问题的。如果不知道什 么是欧拉回路可以看一看欧拉回路的具体定义,这里简单说一下欧拉回路,在一个 无向图中,如果无向图是连通的,如果有两个奇点(被奇数个线来接着的点),则 必须从其中一个奇点出发,另一个奇点终止;如果奇点不存在或有一个奇点,则可 以从任意点出发,最终一定能走完所以结点,称为欧拉回路。用欧拉回路进行判断 可以减去很多无用功,避免超时。
【代码】
#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
int e[1010][1010],Q,P,flag;
void dfs(int cur,int s)
{
if(flag==1)
return ;
int i;
if(s==Q)
{
flag=1;
printf("Yes\n");
return;
}
for(i=1;i<=P;i++)
{
if(e[cur][i]==1)
{
e[cur][i]=0;
e[i][cur]=0;
dfs(i,s+1);
e[cur][i]=1;
e[i][cur]=1;
}
}
return ;
}
int main()
{
int N,x;
scanf("%d",&N);
while(N--)
{
int arr[1010]={0},tmp;
flag=0,x=0;
scanf("%d %d",&P,&Q);
int i,j,a,b;
memset(e,0,sizeof(e));
for(i=1;i<=P;i++)
for(j=1;j<=P;j++)
if(i==j) e[i][j]=0;
else e[i][j]=INF;
for(i=1;i<=Q;i++)
{
scanf("%d %d",&a,&b);
arr[a]++; // 新定义一个数组用来储存输入的数,出来的次数
arr[b]++;
e[a][b]=1;
e[b][a]=1;
}
for(i=1;i<1010;i++)
{
if(arr[i]%2==1) // 求出有多少个奇点(一个点由奇数个线连接)
{
tmp=i;
x++;
}
}
if(x>2)
// 如果出来奇数的个数大于2个说明没有结果,他们只有一个入口没有出口,所以超过2个肯定画不完
{
printf("No\n");
continue;
}
if(x==2||x==1)
dfs(tmp,0); // 如果有2个或1个出现一次的,只可能从一个开始从另一个结束,不然不可能画完
else
dfs(1,0); // 如果都是出现次数大于1,就相当于一个环,从哪开始都一样
if(flag==0)
printf("No\n");
}
return 0;
}
有问题不用找警察,给我留言就OK了