标题链接
标题描述
布置宴席最奇妙的事情,就是给前来参宴的各位来宾组织座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告知主人他们是否能被组织同席
。
输入格局:
输入榜首行给出3个正整数:N(≤100)
,即前来参宴的来宾总人数,则这些人从1
到N
编号;M
为已知两两来宾之间的联系数;K
为查询的条数。随后M
行,每行给出一对来宾之间的联系,格局为:来宾1 来宾2 联系,其中联系为1
表明是朋友,-1
表明是死对头。注意两个人不可能既是朋友又是敌人。最终K
行,每行给出一对需要查询的来宾编号。这里假定朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只要单纯直接的仇视联系才是肯定不能同席的。
输出格局:
对每个查询输出一行结果:假如两位来宾之间是朋友,且没有仇视联系,则输出No problem
;假如他们之间并不是朋友,但也不仇视,则输出OK
;假如他们之间有仇视,然而也有一起的朋友,则输出OK but...
;假如他们之间只要仇视联系,则输出No way
。
输入样例:
7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2
输出样例:
No problem
OK
OK but...
No way
解题思路
首先,标题很长,咱们看过标题后一定要搞清楚要干什么,理清思路,再将代码实现。我做这道题是,没有看完整标题的意思,就去做了,结果输出时遇到问题,又补救代码,浪费时间。
给定N个人,再给出M个两两联系,咱们可以用一个二维数组p来记录每两个人之间的联系,默以为0。最主要的部分就是这句话这里假定朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只要单纯直接的仇视联系才是肯定不能同席的。
最终输出时也要求咱们要判别是否有一起的朋友,所以就用到了并查集
的常识。最终就是处理输入输出的问题。
并查集 (对调集进行兼并和查询)
int f[1000];//x的父结点
int find(int x)//找祖先结点
{
if (f[x] != x) f[x] = find(f[x]);
return f[x];
}
//初始时,每个结点祖先结点初始化为自己
for (int i = 1; i <= n; i++) f[i] = i;
//兼并调集 假如两人之间是朋友则将两人树立联系。
if (c==1 && f[a] != f[b]) f[find(a)] = find(b);
//查询 两人之间仇视,有公共朋友则输出榜首句,没有公共朋友输出第二句。
if (p[a][b] == -1 && find(a) == find(b)) cout << "OK but..."<<endl;
else if(p[a][b] == -1 && find(a) != find(b)) cout << "No way" << endl;
AC代码
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
typedef long long ll;
int p[1000][1000] = {0};
int f[1000];//x的父结点
int find(int x)//找祖先结点
{
if (f[x] != x) f[x] = find(f[x]);
return f[x];
}
int main()
{
int n,m,k;
cin >> n >> m >> k;
//每个结点祖先结点初始化为自己
for (int i = 1; i <= n; i++) f[i] = i;
while (m--)
{
int a, b, c;
cin >> a >> b >> c;
p[a][b] = p[b][a] = c;
//兼并调集
if (c==1 && f[a] != f[b]) f[find(a)] = find(b);
}
while (k--)
{
int a, b;
cin >> a >> b;
if (p[a][b] == 1) cout << "No problem" << endl;
else if (p[a][b] == 0) cout << "OK" << endl;
else if (p[a][b] == -1 && find(a) == find(b)) cout << "OK but..."<<endl;
else if(p[a][b] == -1 && find(a) != find(b)) cout << "No way" << endl;
}
return 0;
}