题目
答案
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int pre[1005],n,m;
vector<int> vec[1005];
int Find(int x)
{
if(pre[x]==-1) return x;
else return pre[x]=Find(pre[x]);
}
void combine(int x,int y)
{
int tmp1=Find(x),tmp2=Find(y);
if(tmp1!=tmp2)
{
pre[tmp2]=tmp1;
}
}
int main()
{
cin>>n>>m;
memset(pre,-1,sizeof pre);
while(m--)
{
int x,y;
cin>>x>>y;
combine(x,y);
vec[x].push_back(y);
vec[y].push_back(x);
}
int cnt1=0,cnt2=0;//cnt1统计奇数点,cnt2统计根点
for(int i=1;i<=n;i++)
{
if(vec[i].size()%2) cnt1++;
if(Find(i)==i) cnt2++;
}
if(cnt1==0&&cnt2==1) printf("1");
else printf("0");
}
总结
这道题采用的是并查集的方法,每个节点的度数就是它向量的size
但需要注意的是,这道题的Find函数如果使用循环,会出现运行超时的问题
循环代码如下:
int Find(int x)
{
while(pre[x]!=-1)
x=pre[x];
return x;
}
所以我们要对Find函数优化,将其改为改良版的递归
代码如下:
int Find(int x)
{
if(pre[x]==-1) return x;
else return pre[x]=Find(pre[x]);
}
大家可能会问,常理上,递归不是比循环慢吗?怎么反而能节约时间呢?
因为,递归的Find函数,除了实现Find外,还有一个作用就是优化
我们来看这行代码:
else return pre[x]=Find(pre[x]);
引用一下大佬的话:这句是先把find到的x赋值给pre[x]的,查找路径上的每个点,下一次找的时候,就能直接找到终点了
再解释一下就是因为此函数找到值为-1的节点就返回,所以所有的节点在递归的赋值中最终都指向了值为-1的节点,为后续的Find节约了时间