一笔画问题
-
描述
-
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)表示测试数据的组数。
上篇用的是深搜,但是这一笔画不用并查集做就不叫做过这一笔画
而且建图的话 数组开的太大,数组的利用率也不高,如果数据较大,那不敢相信;
还是要用一下并查集了,而且这是学习并查集的好机会
简单的并查集
开一个数组,然后将数组初始化
初始化就是将数组里的值改为下标的值
如 a1 里面的值为1 a2 的值为2;
然后 当后面输入 路径(两点连接情况)时,
如果两个点相连,将数组里面的数变为同一个数
如 1 - 3
那么把 a1 和a3 里面的数变为 1 (3也可以,不过后面的都要这样变)
再来一组 1- 4 a1 a4都要变成1(或者3)
数组里面数相同的表示同一个数
如果来一组 2 - 6 那么 a2 与 a6 都为 2 (或者为6)
这样 目前有两组了;
下面先具体实现用此方法的 判断连通图
#include<stdio.h>
int point,line;
int a[1005],m[1005],n[1005];
int bh(int a,int b)
{
if(a>=b)
{
return b;
}
else
{
return a;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int flag=1;
scanf("%d%d",&point,&line);
for(int i=1; i<=point; i++) //这里的i=1 i<=point 不可以换成i=0 i<point
{
a[i]=i;
}
for(int i=0; i<line; i++) //输入的同时开始合并一些集合
{
scanf("%d%d",&m[i],&n[i]);
a[m[i]]=bh(a[m[i]],a[n[i]]);
a[n[i]]=bh(a[m[i]],a[n[i]]);
}
for(int i=1; i<point; i++) //同上 不可以换
{
if(a[i]!=a[i+1])
{
flag=0;
break;
}
}
if(flag==0)
{
printf("NO\n");
}
else
{
printf("YES\n");
}
}
}
这样一个判断是否为连通图的代码就来了
如果是 输出YES 否则NO
但是,刚开始没发现,后来dbug的时候发现了
这样判断连通图是有错误的
如
1
6 6
2 3
3 4
1 2
6 5
4 5
1 6
这组数据是不对的,因为我每一次合并两个集合时只是把这个集合的一个数拉过来
其余的并没有考虑 下面修改代码
下面直接贴上AC代码
#include<stdio.h>
#include<string.h>
int a[1005],d[1005],m[2005],n[2005];
int min(int a,int b)
{
if(a>=b)
{
return b;
}
else
{
return a;
}
}
int max(int a,int b)
{
if(a<=b)
{
return b;
}
else
{
return a;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int point,line,x1,x2;
int flag=1,num=0;
scanf("%d%d",&point,&line);
memset(d,0,sizeof(d));
memset(a,0,sizeof(a));
for(int i=1; i<=point; i++) //初始化
{
a[i]=i;
}
for(int i=1; i<=line; i++) //输入的同时开始合并一些集合
{
scanf("%d%d",&m[i],&n[i]);
x1=max(a[m[i]],a[n[i]]);
x2=min(a[m[i]],a[n[i]]);
//printf("%d %d\n",x1,x2);
for(int j=1;j<=point ;j++)
{
if(a[j]==x1)
{
a[j]=x2;
}
}
d[m[i]]++;
d[n[i]]++;
/*for(int j=1;j<=point ;j++)
{
printf("%d ",a[j]);
}
printf("\n");*/
}
for(int i=1; i<point; i++) //判断是否为连通图
{
if(a[i]!=a[i+1])
{
flag=0;
break;
}
}
for(int i=1; i<=point; i++)
{
if(d[i]%2==1)
{
num++;
}
}
//printf("%d\n",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;
}
错误之处就是修改时 要从头遍历一遍,如果符合修改条件 那就一块修改了,不能只修改一个
啊啊啊,这并查集我怎么觉得比递归还时间长
每输入一个就要从头便利一遍,是不是我方法错误的
下一篇文章我再来一遍这道题,并查集优化法
这篇比较惨