并查集的应用

  重学并查集,该会的一些操作还是得会。。。

1.路径压缩

2.按秩合并

都略了,一道亲戚两者都用,代码:

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
#include<deque>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void put(int x)
{
    if(x==0){putchar('0');putchar('\n');return;}
    if(x<0)putchar('-'),x=-x;
    int num=0;char ch[50];
    while(x)ch[++num]=x%10+'0',x/=10;
    while(num)putchar(ch[num--]);
    putchar('\n');return;
}
const int maxn=5002;
int n,m,k;
int f[maxn],r[maxn];//按秩合并
int getfather(int x)
{
    if(x==f[x])return x;
    return f[x]=getfather(f[x]);
}
void merge(int x,int y)
{
    if(r[x]>=r[y])f[y]=x,r[x]=max(r[x],r[y]+1);
    else f[x]=y,r[y]=max(r[x]+1,r[y]);
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();k=read();
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        x=read();y=read();
        int xx=getfather(x);
        int yy=getfather(y);
        merge(xx,yy);
    }
    for(int i=1;i<=k;i++)
    {
        int x,y;
        x=read();y=read();
        int xx=getfather(x);
        int yy=getfather(y);
        if(xx!=yy)printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

听说这样每次getfather都是常数级别的,炒鸡快诶!

然后带边权的并查集,银河英雄传大家都听说过,还是不太好相同的代码丢一波。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<set>
#include<map>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int maxn=500002;
int n;
int f[maxn],d[maxn],sz[maxn];
char ch;
int getfather(int x)
{
    if(x==f[x])return x;
    int root=getfather(f[x]);
    d[x]+=d[f[x]];
    return f[x]=root;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++)f[i]=i,sz[i]=1;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>ch;
        x=read();y=read();
        if(ch=='M')
        {
            int xx=getfather(x);
            int yy=getfather(y);
            d[xx]=sz[yy];f[xx]=yy;
            sz[yy]+=sz[xx];
        }
        else 
        {
            int xx=getfather(x);
            int yy=getfather(y);
            if(xx!=yy)printf("-1\n");
            else printf("%d\n",abs(d[x]-d[y])-1);
        }
    }
    return 0;
}
View Code

例题 party game poj 1733 好题

很值得思考的一道题,放到这里啦。。

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
#include<deque>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<stack>
//#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void put(int x)
{
    if(x==0){putchar('0');putchar('\n');return;}
    if(x<0)putchar('-'),x=-x;
    int num=0;char ch[500];
    while(x)ch[++num]=x%10+'0',x/=10;
    while(num)putchar(ch[num--]);
    putchar('\n');return;
}
const int maxn=10002;
int n,m;
int a[maxn<<1],c[maxn<<1],top=0,k=0;
char b[10];
struct wy//闻道玉门犹被遮,应将性命逐轻车
{    
    int l,r,h;
}t[maxn<<1];
int f[maxn],d[maxn];//采用带边权的并查集边权为0则x与f[x]奇偶性相同,边权为1则相反
int getfather(int x)
{
    if(x==f[x])return x;
    int root=getfather(f[x]);
    d[x]=d[x]^d[f[x]];
    return f[x]=root;
// }
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        t[i].l=read()-1;
        t[i].r=read();
        scanf("%s",b+1);
        t[i].h=(b[1]=='e'?0:1);
        a[++top]=t[i].l;
        a[++top]=t[i].r;
    }
    //如果l~r之间区间1为偶数则l-1和r奇偶性相同,为奇数时奇偶性不同.
    sort(a+1,a+1+top);
    for(int i=1;i<=top;i++)if(i==1||a[i]!=a[i-1])c[++k]=a[i];//离散
    for(int i=1;i<=top;i++)f[i]=i;
    memset(d,0,sizeof(d));
    for(int i=1;i<=m;i++)
    {
        int x=lower_bound(c+1,c+1+k,t[i].l)-c;
        int y=lower_bound(c+1,c+1+k,t[i].r)-c;
        int xx=getfather(x);int yy=getfather(y);
        if(xx==yy){if((d[x]^d[y])!=t[i].h){put(i-1);return 0;}}
        else 
        {
            f[xx]=yy;d[xx]=d[x]^d[y]^t[i].h;
        }
    }
    put(m);
    return 0;
}
View Code

当然还可以用并查集的扩展域写。

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
#include<deque>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<stack>
//#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void put(int x)
{
    if(x==0){putchar('0');putchar('\n');return;}
    if(x<0)putchar('-'),x=-x;
    int num=0;char ch[500];
    while(x)ch[++num]=x%10+'0',x/=10;
    while(num)putchar(ch[num--]);
    putchar('\n');return;
}
const int maxn=10000;
int n,m;
int a[(maxn<<1)+2],c[(maxn<<1)+2],top=0,k=0;
char b[10];
struct wy//闻道玉门犹被遮,应将性命逐轻车
{    
    int l,r,h;
}t[(maxn<<1)+2];
int f[(maxn<<1)+2];//采用扩展域并查集
int getfather(int x)
{
    if(x==f[x])return x;
    return f[x]=getfather(f[x]);
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        t[i].l=read()-1;
        t[i].r=read();
        scanf("%s",b+1);
        a[++top]=t[i].l;
        a[++top]=t[i].r;
        t[i].h=(b[1]=='o')?1:0;
    }
    sort(a+1,a+1+top);
    for(int i=1;i<=top;i++)
        if(i==1||a[i]!=a[i-1])c[++k]=a[i];
    for(int i=1;i<=(maxn<<1);i++)f[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x=lower_bound(c+1,c+1+k,t[i].l)-c;
        int y=lower_bound(c+1,c+1+k,t[i].r)-c;//代表奇数
        int xx=x+maxn;int yy=y+maxn;//代表偶数的
        if(t[i].h==0)
        {
            int u=getfather(x);
            int u1=getfather(yy);
            if(u==u1){put(i-1);return 0;}
            f[getfather(x)]=getfather(y);
            f[getfather(xx)]=getfather(yy);
        }
        else 
        {
            int u=getfather(x);
            int u1=getfather(y);
            if(u==u1){put(i-1);return 0;}
            f[getfather(x)]=getfather(yy);
            f[getfather(y)]=getfather(xx);
        }
    }
    put(m);
    return 0;
}
View Code

并查集的扩展域还有食物链等.

关键是第一条命令不好判断,是这样的如果是1的话x要吃的和y在一起或x本身和y要吃的就矛盾了

2的话是x和y在一起或x和y要吃的在一起就矛盾了,两条即可判断了。

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
#include<deque>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<bits/stdc++.h>
#define inf 50000
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void put(int x)
{
    if(x==0){putchar('0');putchar('\n');return;}
    if(x<0)putchar('-'),x=-x;
    int num=0;char ch[500];
    while(x)ch[++num]=x%10+'0',x/=10;
    while(num)putchar(ch[num--]);
    putchar('\n');return;
}
const int maxn=50002;
int n,m;
int f[maxn<<2];
int ans=0;
int getfather(int x)
{
    if(x==f[x])return x;
    return f[x]=getfather(f[x]);
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=inf*3;i++)f[i]=i;
    for(int i=1;i<=m;i++)
    {
        int p,x,y;
        p=read();x=read();y=read();//cout<<p<<endl;
        if(x>n||y>n){ans++;continue;}
        //x,y同类,xx,yy是捕食的,xxx,yyy是天敌
        int xx=x+inf;int yy=y+inf;
        int xxx=xx+inf;int yyy=yy+inf;
        if(p==1)
        {
            if(x==y){continue;}
            if(getfather(x)==getfather(yy)||getfather(xx)==getfather(y)){ans++;continue;}
            f[getfather(x)]=getfather(y);
            f[getfather(xx)]=getfather(yy);
            f[getfather(xxx)]=getfather(yyy);
        }
        if(p==2)//x吃y
        {
            if(x==y){ans++;continue;}
            if(getfather(x)==getfather(y)||getfather(x)==getfather(yy)){ans++;continue;}
            f[getfather(x)]=getfather(yyy);
            f[getfather(xx)]=getfather(y);
            f[getfather(xxx)]=getfather(yy);
        }
    }
    put(ans);
    return 0;
}
View Code

↖(^ω^)↗

转载于:https://www.cnblogs.com/chdy/p/10120967.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的高校科研信息管理系统实现了操作日志管理、字典管理、反馈管理、公告管理、科研成果管理、科研项目管理、通知管理、学术活动管理、学院部门管理、科研人员管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让高校科研信息管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值