一笔画问题
时间限制:
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>
int m[2005],n[2005],a[1005],max,min,i;
void bcj(int i)
{
if(m[i]>n[i])
{
max=m[i];
min=n[i];
}
else
{
max=n[i];
min=m[i];
}
a[max]=a[a[min]];
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int point,line;
int flag=1;
scanf("%d%d",&point,&line);
for(int j=1; j<=point ; j++)
{
a[j]=j;
}
for(i=1; i<=line; i++)
{
scanf("%d%d",&m[i],&n[i]);
bcj(i);
}
for(int k=1; k<=point ; k++)
{
a[k]=a[a[k]];
}
for(i=1; i<point ; i++)
{
if(a[i]!=a[i+1])
{
flag=0;
break;
}
}
if(flag==1)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
}
很多个for循环,我自己都有点懵,
大神说,让**指向** 这个我还是有点理解的 (想了很长时间,需要先学习链表)
先建立一个数组,如果让 6指向4 那么简单来说就是 a[6]=4
为什么这样那?
如果我们读取到6的话 直接再读 a[6] 就读出4 了 即6下一个数就是4 接下来根据4 又可以读出4的下一个数
这是我对链表的简单理解(非指针链表)
这个就是用的这个原理。
让大的数指向小的数,
具体让大神讲;并查集
......如果你读懂了,你就会发现,我这个代码是错误的
方向都错了
树的并查集是必须找根节点的
这是我想一下午的结果
找出根节点,然后再用根节点指过去
但是有一个压缩
这题其实用不到
但是很有用 我写上了
#include<stdio.h>
int m[2005],n[2005],a[1005],d[1005],max,min,i;
int find(int p)
{
while(p!=a[p]) //寻找根节点
{
a[p]=a[a[p]]; //这就是压缩,所有的树直接指向根节点这样find的时候效率很高
p=a[p];
}
return p;
}
void bcj(int i)
{
if(m[i]>n[i]) //找出最大数和最小数
{
max=m[i];
min=n[i];
}
else
{
max=n[i];
min=m[i];
}
a[find(max)]=find(min);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int point,line;
int flag=1,num=0,sum=0;
scanf("%d%d",&point,&line);
for(int j=0; j<=point ; j++)
{
a[j]=j; //a数组的初始化
d[j]=0; //数组d 初始化为0
}
for(i=1; i<=line; i++)
{
scanf("%d%d",&m[i],&n[i]);
d[m[i]]++; //记录度
d[n[i]]++;
bcj(i);
}
for(int k=1; k<=point ; k++)
{
a[k]=a[a[k]];
}
for(i=1; i<=point ; i++)
{
if(a[i]==i)
{
sum++;
}
}
if(sum>1)
{
flag=0;
}
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;
}
总结,如果不会,就多想,多算
一道题多做几遍,多浪费点时间没关系
只要是值得的,学到东西的
那么这道题就真正做过了