并查集
题目描述
现在有一个并查集,你需要完成合并和查询操作。
输入格式
第一行包含两个整数NN、MM,表示共有NN个元素和MM个操作。
接下来MM行,每行包含三个整数ZiZi、XiXi、YiYi
当Zi=1Zi=1时,将XiXi与YiYi所在的集合合并
当Zi=2Zi=2时,输出XiXi与YiYi是否在同一集合内,是的话输出YY;否则话输出NN
输出格式
如上,对于每一个Zi=2Zi=2的操作,都有一行输出,每行包含一个大写字母,为YY或者NN
输入输出样例
输入
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
输出
N
Y
N
Y
数据规模
对于30%30%的数据,N≤10N≤10,M≤20M≤20;
对于70%70%的数据,N≤100N≤100,M≤1000M≤1000;
对于100%100%的数据,N≤10000N≤10000,M≤200000M≤200000。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 50005
using namespace std;
//get together jihe
int fa[N];
int n;
void init(){
for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void uni(int x,int y){
fa[find(x)]=find(y);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i;
//init();
while(m--){
int a=0,b=0,c=0;
scanf("%d%d%d",&a,&b,&c);
if(a==1){
fa[find(b)]=find(c);
}
else if(a==2){
if(find(b)==find(c)){
printf("Y
");
}
else{
printf("N
");
}
}
}
return 0;
}
图论
链式前向星与vector
基本实现
#include <cstdio>
struct node{
int to,next,val;
}edge[N];
void add(int x,int y,int val1){
e[cnt]=(node){y,head[x],val1};
head[x]=cnt++;
}
memset(head,-1,sizeof(head));
cnt=0;
for(int i=head[x];i!=-1;i=edge[i].next){
int to1=edge[i].to;
//do something
}
My code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 5005
#define M 20005
using namespace std;
int cnt=0,head[N];
struct node{
int to,next,val;
}edge[N];
void add(int x,int y,int val1){
edge[++cnt].next=head[x];
edge[cnt].to=y;
edge[cnt].val=val1;
head[x]=cnt;
}
int main(){
}
memset(head,-1,sizeof(head));
for(int i=head[x];i!=-1;i=edge[i].next){
int to1=edge[i].to;
//do something
}
最小生成树
我觉得他很重要!!!!!!!!
Kruskal (并查集+链式前向星)
//Kraskul
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 5005
#define M 200005
using namespace std;
int cnt=0,head[M],fa[M];//fa维护点的连通性
struct node{
int to,next,val;
}edge[M];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool cmp(node x,node y){
return x.val<y.val;
}
void add(int x,int y,int val1){
edge[++cnt].next=head[x];
edge[cnt].to=y;
edge[cnt].val=val1;
head[x]=cnt;
}
int tgn,tgto,ans;
int main(){
memset(head,-1,sizeof(head));
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&edge[i].next,&edge[i].to,&edge[i].val);
}
//kruskal
sort(edge+1,edge+m+1,cmp);
for(int i=1;i<=m;i++){
tgn=find(edge[i].next);
tgto=find(edge[i].to);
if(tgn==tgto){
continue;
}
//若已经联通,则不需要这一条边
ans+=edge[i].val;
//边权记录答案
fa[tgto]=tgn; //联通tgto和tgn
if(++cnt==n-1){
break;
}
//边为点数减一时停止
}
if(ans!=0) printf("%d",ans);
else printf("orz");
return 0;
}
/*
for(int i=head[x];i!=-1;i=edge[i].next){
int to1=edge[i].to;
//do something
}
*/