PATL2-010 排座位(并查集)

题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805066135879680

思路:题目说 朋友的朋友是敌人,我一开始以为朋友的朋友的朋友的朋友就不是朋友,说的点拗口

我一开始以为例如 如果A,B是朋友,C,D是朋友,B,C是朋友 但是A,C是朋友 但AD就不是 朋友

但实际上A,C是朋友, 已知CD是朋友,所以AD也是朋友

所以用并查集 把所有有朋友关系的人分到一个集合就可以了

关于并查集:

我们可以理解为一个集合都在一个树上,即在一个集合的根节点都是一样的

以这题示例为例

初始化每个点都是一个集合

father[]数组存放根节点 father[i]表示第i个元素的根节点编号 

用enemy[][] 存放敌人数据 enemy[i][j]==1表示i和j是敌人

初始化后: 宾客  1    2   3   4   5   6    7

          根节点     1    2   3   4   5   6    7

   第一个数据 5 6 1, 即5 6 是朋友就找到5,6的根节点 5的根节点是5,6的根节点是6,所以当前5,6根节点不相等, 所以把6的根节点改成5 即father[6] = 5

然后数据全部输入完后,father数组就变成了

数据输入完后: 宾客  1    2   3   4   5   6    7

                 根节点     1    1   1   1   5   5   7

就可以得到1 2 3 4都互为朋友

5 6互为朋友

7 自己是自己的朋友

 然后就可以enemy数组判断是否是敌人, 通过根节点是否相同判断是否为朋友 就可以完成本题了

 

代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
#include<set>
using namespace std;
int n,m,k;
int father[101];
int enemy[101][101]; //表示enemy[i][j]表示i,j是敌对关系 
int getFather(int x){
    int r = x;
    while(father[r]!=r){
        r = father[r];
    }
//    father[x] = r;
    return r;
}

void Union(int x,int y){
    int fx = getFather(x);
    int fy = getFather(y);
    if(fx!=fy){
        father[fy] = fx;
    }
}
int main()
{
    cin>>n>>m>>k;
    int p1,p2,gx;
    memset(enemy,0,sizeof(enemy));
    for(int i=1;i<=n;i++){
        father[i] = i;
    } 
    for(int i=1;i<=m;i++){
        cin>>p1>>p2>>gx;
        if(gx==-1){
            enemy[p1][p2] = 1;
            enemy[p2][p1] = 1;
        }else{
            Union(p1,p2);
        }
    }
    for(int i=1;i<=k;i++){
        cin>>p1>>p2; 
        int f1 = getFather(p1);
        int f2 = getFather(p2);
        if(enemy[p1][p2]==1) {//如果是敌对关系 
            if(f1==f2) //是朋友
                cout<<"OK but..."<<endl;
            else
                cout<<"No way"<<endl;
        } else { //如果不是敌对关系
            if(f1==f2) //是朋友
                cout<<"No problem"<<endl;
            else
                cout<<"OK"<<endl;
        }
    } 
    return 0;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值