P1892 [BOI2003]团伙 题解

原题:团伙

由题可知,两个人之间的关系只有 敌人朋友 两种情况

再根据题目,还有两种特殊情况需要判断:

1.我朋友的朋友是我的朋友

2.我敌人的敌人也是我的朋友

先解决情况1:

根据题意,要处理这种关系,很明显要运用并查集,如果两人之间是朋友,将两人所在的集合合并,否则不合并,将所有朋友团伙联合在一起,情况1就解决了。

接下来看情况2:

仔细分析,发现合并之前要先知道敌人的敌人是谁。为此,我们设enermy[x]表示第x个人的敌人,当第i个人与第x个人为敌时,i就与enermy[x]合并,成为朋友,这样情况2就迎刃而解了。

#include<iostream>

using namespace std;
//Problem need(题目所需):
int n,m,x,y;
char z;
//Union-find set need(并查集所需):
int father[1005],en[1005]/*enermy数组*/,ans;
bool b[1005];//记录团伙是否被寻找过

int myfind(int x)//递归方式寻找根
{
    
    
    if(father[x]!=x) father[x]=myfind(father[x]);
    return father[x];
}

void unionn(int x,int y)//合并两人的团伙
{
    
    
    x=myfind(x);
    y=myfind(y);
    father[y]=x;
}

int main()
{
    
    
    cin>>n>>m;
    /*-------初始化-------*/
    for(int i=1;i<=n;i++)
        father[i]=i;//最开始所有人以自己为一个团伙
    /*-------------------*/
    for(int i=1;i<=m;i++)
    {
    
    
        cin>>z>>x>>y;
        if(z=='F')
        {
    
    
            unionn(x,y);//当x与y为朋友时,直接联合
        }
        else//否则就为敌人
        {
    
    
            if(en[x])//如果x有敌人,那么x的敌人与y联合
                unionn(en[x],y);
            else 
                if(en[y])//如果y有敌人,那么y的敌人与x联合
                    unionn(en[y],x);
            en[x]=y;//互相标记为敌人
            en[y]=x;//不用担心覆盖,因为x和y已经连上自己的团伙
        }
    }
    for(int i=1;i<=n;i++)
        if(!b[myfind(i)])//寻找团伙数量
        {
    
    
            ans++;
            b[myfind(i)]=1;
        }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/bell041030/article/details/88765630
今日推荐