题目链接: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;
}