并查集

来源:互联网 发布:怎么让数组置空 编辑:程序博客网 时间:2024/05/30 05:00

FZU2155 带删除并查集

HDU 2473 Junk-Mail Filter 并查集删除(FZU 2155盟国)

http://acm.hdu.edu.cn/showproblem.php?pid=2473

http://acm.fzu.edu.cn/problem.php?pid=2155

题目大意:

编号0~n-1的电子邮件,让你进行归类。

M X Y表示x y是同一类的,而S X则取消之前X的分类。问你经过M次这样的操作后,有多少类相同的邮件。

思路:

下午FZU月赛有这题。不过我没参加- -||||,先暂时退出ACM一段时间。事情多。得先去搞定那个外包的软件了

并查集的应用。多开了一个数组real,记录点的真实存在的位置。

一开始初始化为和fa相同的,删除的时候把原来x所在的位置变为新的一个位置即可,那么原来的集合不受影响。

看代码吧。。

#include<cstdio>#include<cstring>const int MAXN=1100010;int fa[MAXN],real[MAXN];bool vis[MAXN];int find(int x){    if(x!=fa[x])fa[x]=find(fa[x]);    return fa[x];}int main(){    int n,m,kase=1;    while(~scanf("%d%d",&n,&m),n||m)    {        memset(vis,0,sizeof(vis));        int k=n;        for(int i=0;i<n;i++)            real[i]=fa[i]=i;         char cmd[5];        for(int i=0;i<m;i++)        {            scanf("%s",cmd);            if(cmd[0]=='M')            {                int a,b;                scanf("%d%d",&a,&b);                int root_x=find(real[a]),root_y=find(real[b]);                if(root_x!=root_y)                    fa[root_x]=root_y;            }            else            {                int a;                scanf("%d",&a);                fa[k]=k;                real[a]=k++;            }        }        int ans=0;        for(int i=0;i<n;i++)        {            int x=find(real[i]);            if(!vis[x])            {                vis[x]=1;                ans++;            }        }        printf("Case #%d: %d\n",kase++,ans);    }    return 0;}

ZOJ1789最基础的并查集
#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define N 30010int f[N],cnt[N];int n,m;int mfind(int x){    if(f[x]!=x)f[x]=mfind(f[x]);    return f[x];}void make(int a,int b){    int f1=mfind(a);    int f2=mfind(b);    if(f1!=f2)    {        f[f2]=f1;        cnt[f1]+=cnt[f2];    }}int main(){    int i;    while(~scanf("%d%d",&n,&m)&&(n+m))    {        for(i=0;i<=n;i++){            f[i]=i;            cnt[i]=1;        }        int t,a,b;        for(i=0;i<m;i++)        {            scanf("%d",&t);            scanf("%d",&a);            t--;            while(t--)            {                scanf("%d",&b);                make(a,b);            }        }        int p=mfind(0);        printf("%d\n",cnt[p]);      //  for(i=0;i<100;i++)printf("%d %d\n",i,cnt[i]);    }    return 0;}


PAT1034 做了这题后对并查集理解更深刻了些 
题意:

『gang』翻译过来是『一伙人』。gang 的定义是一群人,至少有 3 个人,这群人中每个人之间都通过通话相连,且整个群体的通话时长超过一个阈值。整个 gang 的团体中,拥有的电话时长最长的人就是头目了。



#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<map>#define N 1010using namespace std;map<string,string>f,to;map<string,int>cnt,tot,ans,all;map<string,string>::iterator it;map<string,int>::iterator itt;string mfind(string x){    if(f[x]!=x)f[x]=mfind(f[x]);    return f[x];}void make(string a,string b,int time){    string f1=mfind(a);    string f2=mfind(b);    if(f1!=f2)    {        f[f2]=f1;        cnt[f1]+=cnt[f2];//统计点权        all[f1]+=all[f2]+time;        return;    }    all[f1]+=time;//统计边权}int main(){    int n,k;    while(~scanf("%d%d",&n,&k))    {        f.clear();        cnt.clear();        tot.clear();        ans.clear();        to.clear();        all.clear();        char aa[10],bb[10];        string a,b;        int time;       for(int i=0;i<n;i++)        {            scanf("%s%s%d",aa,bb,&time);            a=aa;            b=bb;            if(f[a]==""){                    f[a]=a;                    cnt[a]=1;                    all[a]=0;            }            if(f[b]==""){                    f[b]=b;                    cnt[b]=1;                    all[b]=0;            }            tot[a]+=time;            tot[b]+=time;            make(a,b,time);        }        //*****---如果没有这一步,下面两个案例的输出结果是不一样的        for(it=f.begin();it!=f.end();it++)        {            it->second=mfind(it->second);        }        //--        for(it=f.begin();it!=f.end();it++)        {            if(cnt[it->second]<=2||all[it->second]<=k)continue;            if(tot[it->first]>ans[it->second]){                    ans[it->second]=tot[it->first];                    to[it->second]=it->first;            }          //  cout<<it->first<<" "<<it->second<<" "<<tot[it->first]<<" "<<cnt[it->second]<<" "<<all[it->second]<<endl;        }        cout<<ans.size()<<endl;        for(itt=ans.begin();itt!=ans.end();itt++)        {            cout<<to[itt->first]<<" "<<cnt[itt->first]<<endl;        }    }    return 0;}/*6 59AAA BBB 10BBB AAA 20AAA CCC 40DDD EEE 5EEE DDD 70BBB DDD 106 59AAA BBB 10BBB AAA 20AAA CCC 40DDD EEE 5BBB DDD 10EEE DDD 70*/





0 0
原创粉丝点击