【NOJ1593、1594、1595】【并查集三连】朋友敌人关系

1593.并查集(一)

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

一个城市中有n个人,其中一些人是朋友关系,同时他们都认为:朋友的朋友是朋友,现在任给两个人,问他们是否是朋友关系。

输入

先输入两个正整数n和m(均小于1000),表示城市里有n个人,并且将给出m对朋友关系,接下来的m行每行给出两个0~n-1之间的整数,表示这两个人是朋友关系。
最后一行再输入两个0~n-1之间的整数,问他们是否是朋友关系。

输出

是朋友关系则输出”Yes”,否则输出”No”。

#include <iostream>

using namespace std;

int a[1000];    //存储并查集
int n,m;

int fsearch(int x); //返回结点x的根节点

int main()
{
    //输入数据
    cin>>n>>m;

    for(int i=0;i<n;i++)
    {
        a[i]=i;    //初始时每个人只和自己做朋友
    }

    int x,y;    //是朋友关系的两个人
    int kx,ky;  //根节点
    for(int i=0;i<m;i++)
    {
        cin>>x>>y;
        //cout<<x<<y;
        kx=fsearch(x);  //x的根节点
        ky=fsearch(y);  //y的根结点
        a[ky]=kx;       //相连
    }

    //输出数据
    cin>>x>>y;
    kx=fsearch(x);  //x的根节点
    ky=fsearch(y);  //y的根结点
    if(kx==ky)
    {
        cout<<"Yes"<<endl;
    }
    else
    {
        cout<<"No"<<endl;
    }
    return 0;
}

int fsearch(int x)
{
    int f=a[x];
    while(f!=a[f])  //若未找到根节点
    {
        f=a[f];     //继续向上搜索
    }
    a[x]=f; //更新a[x]的值,使他离根节点更近,方便下一次搜索
    return f;
}

1594.并查集(二)

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

一个城市中有一些犯罪团伙,共有n个人,有m条信息同伙信息,并且知道同伙的同伙是同伙,问共有多少个犯罪团伙。

输入

先输入两个正整数n和m(均小于1000),表示城市里有n个人,并且将给出m对朋友关系,接下来的m行每行给出两个0~n-1之间的整数,表示这两个人是朋友关系。

输出

输出犯罪团伙的个数。

#include <iostream>

using namespace std;

int a[1000];    //存储并查集-犯罪团伙
int n,m;

int fsearch(int x); //返回x结点的根节点

int main()
{
    cin>>n>>m;

    for(int i=0; i<n; i++)  //初始化并查集
    {
        a[i]=i;
    }

    int x,y;
    int kx,ky;
    for(int i=0; i<m; i++)  //读入数据
    {
        cin>>x>>y;

        kx=fsearch(x);
        ky=fsearch(y);
        a[ky]=kx;
    }

    int cnt=0;    //犯罪团伙个数
    for(int i=0; i<n; i++)
    {
        if(a[i]==i) //数根节点个数
        {
            cnt++;
        }
    }
    cout<<cnt<<endl;
    return 0;
}


int fsearch(int x)   //返回x结点的根节点
{
    int f=x;
    while(f!=a[f])
    {
        f=a[f];
    }

    a[x]=f; //使x结点直接指向其根节点

    return f;
}

1595.并查集(三)

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

一个城市中有n个人,其中一些人是朋友关系,一些人之间是敌人关系,同时他们都认为:朋友的朋友是朋友,敌人的敌人是朋友,(注意:朋友的敌人不一定是敌人),现在任给两个人,问他们是否是朋友关系。

输入

先输入两个正整数n和m(均小于1000),表示城市里有n个人,并且将给出m对朋友或敌人关系,接下来的m行每行三个整数,先给出一个整数0或1(0表示后面这两个人是朋友,1表示是敌人),再给出两个0~n-1之间的整数表示两个人。
最后一行再输入两个0~n-1之间的整数,问这两个人是否是朋友关系。

输出

是则输出”Yes”,否则输出”No”。

#include <iostream>

using namespace std;

int a[1000];    //朋友并查集
int b[1000][1000];      //存储敌人关系
int n,m;

int fa_search(int x);   //返回并查集a里x的根节点

void fa_add(int x, int y);  //将x和y添加成朋友关系
void fb_add(int x, int y);  //将x和y添加成敌人关系

void f_add(int x, int y);   //将y的敌人与x添加成朋友关系
                            //(敌人的敌人是朋友)

int main()
{
    cin>>n>>m;

    for(int i=0; i<n; i++)  //初始化并查集
    {
        a[i]=i;
    }

    int p,x,y;
    int kx,ky;
    for(int i=0; i<m; i++)  //输入数据
    {
        cin>>p>>x>>y;
        if(p==0)    //x和y是朋友
        {
            fa_add(x, y);
        }
        else        //x和y是敌人
        {
            //在b中添加敌人关系
            fb_add(x, y);

            //y的所有敌人是x的朋友
            f_add(x, y);

            //x的所有敌人是y的朋友
            f_add(y, x);
        }
    }

    cin>>x>>y;
    kx=fa_search(x);
    ky=fa_search(y);
    if(kx==ky)              //输出数据
    {
        cout<<"Yes"<<endl;
    }
    else
    {
        cout<<"No"<<endl;
    }

    return 0;
}

int fa_search(int x)    //返回并查集a里x的根节点
{
    int f=a[x];
    while(f!=a[f])
    {
        f=a[f];
    }
    a[x]=f;     //更新a[x]
    return f;
}

void fa_add(int x, int y)   //将x和y添加成朋友关系
{
    int kx,ky;
    kx=fa_search(x);
    ky=fa_search(y);
    a[ky]=kx;
}

void fb_add(int x, int y)   //将x和y添加成敌人关系
{
    b[x][y]=1;
    b[y][x]=1;
}


void f_add(int x, int y)    //将y的敌人与x添加成朋友关系
{                           //(敌人的敌人是朋友)
    for(int i=0; i<n; i++)
    {
        if(i!=x&&i!=y)
        {
            if(b[y][i]==1)  //若y和i是敌人关系
            {
                fa_add(x,i);    //那么x和i是朋友关系
            }
        }
    }
}

【后记】

1.并查集(四)吭哧半天没写出来,好气啊,待续

    原文作者:犯罪团伙问题
    原文地址: https://blog.csdn.net/qq_41727666/article/details/82952257
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞