20200116

并查集

题目描述

现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数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%的数据,N10N≤10,M20M≤20;
对于70%70%的数据,N100N≤100,M1000M≤1000;
对于100%100%的数据,N10000N≤10000,M200000M≤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
}
*/
原文地址:https://www.cnblogs.com/ziyuan122625/p/12213625.html