如果这一题蛮力求解,会很复杂,关系网都能把自己弄晕,所以采取简化的算法----并查集
所以你需要弄清楚并查集算法
概念:即支持对集合进行合并和查询的一个数据结构
合并:将元素a和元素b所在的集合合并成一个集合
查询:查询a和b是否为同一集合
如图:
引入一个父亲数组parent[i],parent[i]表示第i个元素所在的集合
初始化:最开始时每个元素都在各自的集合里,即parent[i] = i
合并:如果要合并集合a和b,就把所有a所在的集合的所有元素合并到b所在的集合
查询:查询(a,b)是否在同一个集合里,就查询parent[a]是否等于parent[b],也就是a和b是否为同一父亲即可
如图:
算法实现
初始化:
void init(int *a, int n)
{
for(int i = 0; i < n; ++i)//每个元素自成一个集合
{
a[i] = i;
}
}
合并:
void uni(int *a, int p, int q, int n)
{
//将集合a中元素都并在集合b之中
int pid = a[p];
int qid = a[q];
for(int i = 0; i < n; ++i)
{
if(a[i] == qid)
{
a[i] = pid;
}
}
}
查询:
bool connected(int *a, int p, int q)
{
if(a[p] == a[q])
return true;
else
return false;
}
再来看排座位这一题:
布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。
输入格式:
输入第一行给出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
这一题的查询有一些难度,需要用到递归,if(parent[i] == i) return i;可以直接返回,但是还有一种情况就是需要找到它的父亲,因为它是经过合并之后,这时index = GetOriNode(parent[i]) return index;其余部分就没什么难度了
代码如下:
#include <iostream>
using namespace std;
#define MAXN 105
int dp[MAXN][MAXN];
int parent[MAXN];
void Init_Parent_Real(int n)
{
int i, j;
for(i = 1; i <= n; ++i)
{
parent[i] = i;
for(j = 1; j <= n; ++j)
{
dp[i][j] = 0;
}
}
}
int GetOriNode(int pos)
{
if(parent[pos] == pos)
{
return pos;
}
int index = GetOriNode(parent[pos]);
return index;
}
int Union(int m1, int m2)
{
if(GetOriNode(m1) != GetOriNode(m2))
{
int index = GetOriNode(m1);
parent[index] = GetOriNode(m2);
}
}
int main()
{
int i, n, m, k, r1, r2, customer1, customer2, relation;
scanf("%d%d%d", &n, &m, &k);
Init_Parent_Real(n);
for(i = 0; i < m; ++i)
{
scanf("%d%d%d", &customer1, &customer2, &relation);
dp[customer1][customer2] = relation;
dp[customer2][customer1] = relation;
if(relation == 1)
{
Union(customer1, customer2);
}
}
i = 0;
while(i < k)
{
scanf("%d%d", &r1, &r2);
if(dp[r1][r2] == 1) printf("No problem\n");
else if(dp[r1][r2] == -1)
{
if(GetOriNode(r1) == GetOriNode(r2)) printf("OK but...\n");
else printf("No way\n");
}
else
{
printf("OK\n");
}
++i;
}
return 0;
}
OK!