一笔画问题
-
描述
-
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、判断点是奇点的个数,就可以了。(1)判断连通图(个人觉得,这弄好了,这道题也就完了)
方法(1)
递归,对,就是递归,递归一下,看能递归到所有数不,如果不是连通的递归会中断,有的数就不会被递归到
递归还有一个问题就是要建图,建图的目的就是保存那些连通的点,
总不能每递归一次就要从头遍历一遍找下一个点吧,那样妥妥的超时,
而我们要做的就是找一种方法,让我们能最快的找到我们想要的点,那就是建图
#include<stdio.h>
#include<string.h>
int point,line;
bool map[1005][1005];
bool vis[1005];
int a[2000],b[2000];
int dfs(int x)
{
vis[x]=true;
for(int j=1;j<=point;j++)//图的同一行向右找
{
if(map[x][j]==true)//如果找到,继续递归
{
dfs(j);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int flag=1;
scanf("%d%d",&point,&line);
memset(map,false,sizeof(map));//初始化
memset(vis,false,sizeof(vis));
for(int i=0;i<line;i++)
{
scanf("%d%d",&a[i],&b[i]);
map[a[i]][b[i]]=true; //输入的同时开始建图
map[b[i]][a[i]]=true;
}
dfs(a[0]); //开始递归
for(int i=1;i<=point;i++) //如果所有的点都递归过,flag=1;
{
if(vis[i]==false)
{
flag=0;
}
}
if(flag==0)
{
printf("NO\n");
}
else
{
printf("YES\n");
}
}
}
初步的就出来了,但是还不行
输入样例就错了,进入了死循环
if(map[x][j]==true&&vis[j]==false)//如果找到,继续递归
好了 加一点,成了,
下面判断一下是否能一笔画完
简单说一下我对 欧拉结论的理解
首先说几个概念 (1)度; 一个点的度 指跟这个点相连的线的条数
如第一个样例,画个图,点1的度是3 其余的点的度都是1;
(2)奇点,度为1的点为奇点;
(3)偶点,度为偶数的点;
点是可以多次经过的,而边只能过一次,
打个比方,每个点是一个车站,而边是路,车每走一次这条路,路就塌陷了(豆腐渣工程)
先不看出发点,和终点;
偶数点有个特点是,对于这个车站来说,车不论经过这个车站多少次,车最后都能出去,
奇数点就不一样了,车总会被困在这个车站
如果想让车不被困在奇数点,唯一的办法就是这个奇数点是出发点,或者终点
那么,奇数点只能有两个,
所以 第一种情况就出来了
2个奇数点,其余全是偶数点,而且奇数点必须是发车点和终点
你问我为啥不会是 一个奇数点,其余全是偶数点,哈!因为不可能是这种情况啊
1条边需要两个度,边是整数,那总度(所有点度之和)肯定是偶数,这情况 总度都不是偶数
第二种情况
所有的点都是偶数,根据上面说的,偶数点的特点就是,车不会卡死在这里
那所有的点都是这样,不会卡死车,那车哪能跑不完全程那,对吧!
对于终点和出发点,必须是同一个点(而且肯定是)
这样 所有情况咱都考虑完了
总结一下;
(1) 奇数点肯定不能超过2个;
(2)奇数点为1个的情况不存在
(2)偶数可以随便有;
上面搞完数学了,该搞代码了
就计算一个各个点的度,判断一下上面的情况
#include<stdio.h>
#include<string.h>
int point,line;
bool map[1005][1005];
bool vis[1005];
int a[2005],b[2005],d[1005];
int dfs(int x)
{
vis[x]=true;
for(int j=1; j<=point; j++) //图的同一行向右找
{
if(map[x][j]==true&&vis[j]==false)//如果找到,继续递归
{
dfs(j);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int flag=1,num=0;
scanf("%d%d",&point,&line);
memset(map,false,sizeof(map));//初始化
memset(vis,false,sizeof(vis));
for(int i=0; i<line; i++)
{
scanf("%d%d",&a[i],&b[i]);
map[a[i]][b[i]]=true; //输入的同时开始建图
map[b[i]][a[i]]=true;
d[a[i]]++; //同时开始统计度
d[b[i]]++;
}
dfs(a[0]); //开始递归
for(int i=1; i<=point; i++) //如果所有的点都递归过,flag=1;
{
if(vis[i]==false)
{
flag=0;
}
}
for(int i=1; i<=point; i++)
{
if(d[i]%2==1)
{
num++;
}
}
if(flag==1)
{
if(num==2||num==0)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
else
{
printf("No\n");
}
}
return 0;
}
.....提交是WA......
下面DBUG
....忘记给数组 d 清零了
老毛病
AC代码
#include<stdio.h>
#include<string.h>
int point,line;
bool map[1005][1005];
bool vis[1005];
int a[2005],b[2005],d[1005];
int dfs(int x)
{
vis[x]=true;
for(int j=1; j<=point; j++) //图的同一行向右找
{
if(map[x][j]==true&&vis[j]==false)//如果找到,继续递归
{
dfs(j);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int flag=1,num=0;
scanf("%d%d",&point,&line);
memset(map,false,sizeof(map));//初始化
memset(vis,false,sizeof(vis));
memset(d,0,sizeof(d));
for(int i=0; i<line; i++)
{
scanf("%d%d",&a[i],&b[i]);
map[a[i]][b[i]]=true; //输入的同时开始建图
map[b[i]][a[i]]=true;
d[a[i]]++; //同时开始统计度
d[b[i]]++;
}
dfs(a[0]); //开始递归
for(int i=1; i<=point; i++) //如果所有的点都递归过,flag=1;
{
if(vis[i]==false)
{
flag=0;
}
}
for(int i=1; i<=point; i++)
{
if(d[i]%2==1)
{
num++;
}
}
if(flag==1&&point>1)
{
if(num==2||num==0)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
else if(point==1)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}
不过这次dbug
花了不到10分钟,进步,继续坚持