题解
就是并查集判断,是否存在环,若存在则不符合题意
#include <iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e6+10;
int pre[N]; //每个结点
int ranks[N]; //树的高度
int vis[N];
//初始化
void init(int n) //对n个结点初始化
{
for(int i = 1; i <=n; i++){
pre[i] = i; //每个结点的上级都是自己
ranks[i] = 1; //每个结点构成的树的高度为1
}
}
/*
int find_pre(int x) //查找结点x的根结点
{
if(pre[x] == x){ //递归出口:x的上级为x本身,即x为根结点
return x;
}
return find_pre(pre[x]); //递归查找
}
*/
//改进查找算法:完成路径压缩,将x的上级直接变为根结点,那么树的高度就会大大降低
int Find_pre(int x) //查找结点x的根结点
{
if(pre[x] == x){ //递归出口:x的上级为x本身,即x为根结点
return x;
}
return pre[x] = Find_pre(pre[x]); //递归查找 此代码相当于 先找到根结点rootx,然后pre[x]=rootx
}
bool is_same(int x, int y) //判断两个结点是否连通
{
return Find_pre(x) == Find_pre(y); //判断两个结点的根结点(亦称代表元)是否相同
}
int unite(int x,int y)
{
int rootx, rooty;
rootx = Find_pre(x);
rooty = Find_pre(y);
if(rootx == rooty){
return false;
}
if(ranks[rootx] > ranks[rooty]){
pre[rooty] = rootx; //令y的根结点的上级为rootx
}
else{
if(ranks[rootx] == ranks[rooty]){
ranks[rooty]++;
}
pre[rootx] = rooty;
}
return true;
}
int main()
{
while(true)
{
int x,y,ans=0,cnt=0,sum=0,falg=1;
memset(vis,0,sizeof(vis));
while(cin>>x>>y)
{
if(x==0&&y==0||x==-1&&y==-1)
break;
cnt++;
if(vis[x]==0)
{
ans++;
pre[ans]=ans;
ranks[ans]=1;
vis[x]=ans;
}
if(vis[y]==0)
{
ans++;
pre[ans]=ans;
ranks[ans]=1;
vis[y]=ans;
}
if(!unite(vis[x],vis[y]))
{
falg=0;
}
}
if(x==-1&&y==-1)
break;
if(falg==0)
{
cout<<"No"<<endl;
continue;
}
for(int i=1;i<=ans;i++)
{
if(pre[i]==i)
sum++;
if(sum>1)
break;
}
if(sum>1)
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
}
//cout << "Hello world!" << endl;
return 0;
}
一开始直观感觉就是分情况讨论
当不符合,边数等于房间数减一,的规律的话一定不符合
然后就是并查集判断是否能联通
但是只能过一部分数据,还有一部分被重复的房间路径给卡掉了
非AC代码:
#include <iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e6+10;
int pre[N]; //每个结点
int ranks[N]; //树的高度
int vis[N];
//初始化
void init(int n) //对n个结点初始化
{
for(int i = 1; i <=n; i++){
pre[i] = i; //每个结点的上级都是自己
ranks[i] = 1; //每个结点构成的树的高度为1
}
}
/*
int find_pre(int x) //查找结点x的根结点
{
if(pre[x] == x){ //递归出口:x的上级为x本身,即x为根结点
return x;
}
return find_pre(pre[x]); //递归查找
}
*/
//改进查找算法:完成路径压缩
//,将x的上级直接变为根结点,那么树的高度就会大大降低
int Find_pre(int x) //查找结点x的根结点
{
if(pre[x] == x){ //递归出口:x的上级为x本身,即x为根结点
return x;
}
return pre[x] = Find_pre(pre[x]);
//递归查找 此代码相当于 先找到根结点rootx,然后pre[x]=rootx
}
bool is_same(int x, int y) //判断两个结点是否连通
{
return Find_pre(x) == Find_pre(y);
//判断两个结点的根结点(亦称代表元)是否相同
}
void unite(int x,int y)
{
int rootx, rooty;
rootx = Find_pre(x);
rooty = Find_pre(y);
if(rootx == rooty){
return ;
}
if(ranks[rootx] > ranks[rooty]){
pre[rooty] = rootx; //令y的根结点的上级为rootx
}
else{
if(ranks[rootx] == ranks[rooty]){
ranks[rooty]++;
}
pre[rootx] = rooty;
}
}
int main()
{
while(true)
{
int x,y,ans=0,cnt=0,sum=0;
memset(vis,0,sizeof(vis));
//init(ans);
while(cin>>x>>y)
{
if(x==0&&y==0||x==-1&&y==-1)
break;
cnt++;
if(vis[x]==0)
{
ans++;
pre[ans]=ans;
ranks[ans]=1;
vis[x]=ans;
}
if(vis[y]==0)
{
ans++;
pre[ans]=ans;
ranks[ans]=1;
vis[y]=ans;
}
unite(vis[x],vis[y]);
}
if(x==-1&&y==-1)
break;
if(ans!=cnt+1)
{
cout<<"No"<<endl;
// cout<<ans;
continue;
}
for(int i=1;i<=ans;i++)
{
if(pre[i]==i)
sum++;
if(sum>1)
break;
}
if(sum>1)
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
}
//cout << "Hello world!" << endl;
return 0;
}