寒·Kun @ 2018-07-21 19:50:52
转自 @封禁用户f8617dda的博客
定义如下:
struct Node{
int father;//父亲
}s[MAXN];//数组
错误代码如下:
switch(z){
case 1:{
s[y].father=x;
break;
}
case 2:{
if(s[y].father==x||s[x].father==y){
printf("Y\n");
}else{
printf("N\n");
}
break;
}
}
千万不可以这样!
所以就用到了并查列中的化简:就是如果一个树找目前的父亲,一定会找到这棵树的根。然而在查找的过程中,就可以把他的父亲的父亲标示移到他找到的根,这样一直下去就行了。
有需要知识课件的,私聊我( 封禁用户名f8617dda)
by Nero_Claudius @ 2018-07-21 19:57:36
@美玉无瑕 这玩意叫并查集Union Set。。。
by Nero_Claudius @ 2018-07-21 20:00:06
还有判断是否有共同祖先这样不就行了吗:
int find(int x){return (x==f[x])?x:f[x]=find(f[x])}
if(find(x)==find(y))cout<<"Y\n";
cout<<"N\n";
by 御·Dragon @ 2018-07-21 20:02:12
@DARTH_VADER 大佬我们交朋友把
by Taduro @ 2018-07-21 20:09:41
而且并查集肯定是路径压缩啊
by kitakami @ 2018-07-21 20:14:04
%%%大佬都学到并查列了,我才学到动态划分
by AThousandSuns @ 2018-07-21 20:14:28
@多弗桃 按秩合并教你做人(可持久化的毒瘤卡空间)
by 御·Dragon @ 2018-07-21 20:17:25
@DARTH_VADER @多弗桃 @AThousandSuns
求助!
#include<bits/stdc++.h>
using namespace std;
const int MAXN=200010;
struct Node{
int father;
int d;
}s[MAXN];
int n,m,z,x,y,k;
int dg(int p,int o){
if(s[p].father==o)return 1;
if(s[p].father!=s[p].d){
p=s[p].father;
dg(p,o);
}
if(s[p].father==s[p].d)return 0;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
s[i].d=i;
}
for(int i=1;i<=m;i++){
scanf("%d",&z);
scanf("%d %d",&x,&y);
switch(z){
case 1:{
s[y].father=x;
break;
}
case 2:{
if(dg(y,x))printf("Y\n");
else printf("N\n");
break;
}
}
}
return 0;
}
by 御·Dragon @ 2018-07-22 10:21:12
@DARTH_VADER @多弗桃 @萝莉大法好 @AThousandSuns
改了一下,再次求助
#include<bits/stdc++.h>
using namespace std;
const int MAXN=20010;
int s[MAXN];
int n,m,z,x,y,k;
int fin(int p){
if(s[p]==0)return p;
fin(s[p]);
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
scanf("%d",&z);
scanf("%d %d",&x,&y);
switch(z){
case 1:{
s[y]=x;
break;
}
case 2:{
if(fin(y)==fin(x))printf("Y\n");
else printf("N\n");
}
}
}
return 0;
}
//样例过了,但10分
by Nero_Claudius @ 2018-07-22 10:31:16
@封禁用户名f8617dda 本人AC代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N=10010;
int n,m,z,x,y;
struct Unionset{
private:
int f[N];
public:
Unionset(){
for(int i=1;i<=n;i++)f[i]=i;
}
int find(int x){if(x==f[x])return x;return f[x]=find(f[x]);}
void merge(int x,int y){x=find(x),y=find(y);if(x!=f[y])f[y]=x;return;}
};
int main(){
cin>>n>>m;
Unionset U;
for(int i=0;i<m;i++){
cin>>z>>x>>y;
if(z==1)U.merge(x,y);
else{if(U.find(x)==U.find(y))cout<<"Y\n";else cout<<"N\n";}
}return 0;
}
by 御·Dragon @ 2018-07-22 10:34:38
@DARTH_VADER 当然感谢你的好意,但是只要求用本人的超烂算法搞懂就行了。谢谢!