PAT 天梯赛 L2-016. 愿天下有情人都是失散多年的兄妹 【BFS】

本文介绍了一种利用BFS(宽度优先搜索)算法解决特定血缘关系判断问题的方法。通过构建家族成员间的关系图,并使用队列实现逐代遍历检查,确保能够准确判断任意两人间的血缘联系是否超过五代。文章详细解释了如何处理特殊情况,例如当祖先信息缺失时的判断逻辑。

题目链接

https://www.patest.cn/contests/gplt/L2-016

思路
用BFS 每层 遍历当代 并且查找当代是否有重复 有重复就跳出 然后 POP 并且将他们的下一代 压入 队列
但是有一个点 要注意
就是 如果存在两个人 他们的上一代 都不可考
那么就默认没有血缘关系
那么就要根据 性别来判断
如果 这两个人 是出现在 某个人的父亲 或 母亲中呢 所以在输入的时候 对于父亲和母亲的性别是没有标记的 那么就会出错
所以要加入 父亲和母亲的性别标记

其实还有种简单的方法 就是用SET就可以了 两个 分别压入 然后判断 SET的大小有没有改变 如果没有改变 就是有重复

或者 用数组标记

AC代码

#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>

using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;

const double PI = 3.14159265358979323846264338327;
const double E = exp(1);
const double eps = 1e-6;

const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 5;
const int MOD = 1e9 + 7;

map <int, pii> m;
map <int, int> judge[2];

queue <int> q[2];

int ans;

void bfs(int cur)
{
    if (cur == 7)
        return;
    for (int i = 0; i < 2; i++)
    {
        judge[i].clear();
        while (!q[i].empty())
        {
            int num = q[i].front();
            q[i].pop();
            if (num != -1)
                judge[i][num] = 1;
        }
    }
    map <int, int>::iterator it;
    for (it = judge[0].begin(); it != judge[0].end(); it++)
    {
        if (judge[1][it->first])
        {
            ans = cur;
            return;
        }
        else
            judge[1].erase(it -> first);
    }
    for (int i = 0; i < 2; i++)
    {
        for (it = judge[i].begin(); it != judge[i].end(); it++)
        {
            if (m[it->first].first != -1)
                q[i].push(m[it->first].first);
            if (m[it->first].second != -1)
                q[i].push(m[it->first].second);
        }
    }
    bfs(cur + 1);
}

int main()
{
    map <int, int> vis, opt;
    int n;
    scanf("%d", &n);
    int a, b, c, d;
    char code;
    for (int i = 0; i < n; i++)
    {
        scanf("%d %c %d %d", &a, &code, &b, &c);
        opt[a] = 1;
        if (code == 'M')
            vis[a] = 0;
        else
            vis[a] = 1;
        m[a].first = b;
        if (b != -1)
        {
        if (opt[b] == 0)
        {
            m[b].first = -1;
            m[b].second = -1;
        }
        vis[b] = 0;         
        }
        m[a].second = c;
        if (c != -1)
        {
        if (opt[c] == 0)
        {
            m[c].first = -1;
            m[c].second = -1;
        }
        vis[c] = 1;         
        }
    }
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d", &a, &b);
        if (vis[a] == vis[b])
            printf("Never Mind\n");
        else
        {
            while (!q[0].empty())
                q[0].pop();
            while (!q[1].empty())
                q[1].pop();
            q[0].push(a);
            q[1].push(b);
            ans = INT_MAX;
            bfs(1);
            if (ans > 5)
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
}
### L2-016 天下有情人都是失散多年兄妹 测试点解析 此题的核心在于判断两人性别以及他们在家族关系中的近亲程度。以下是关于该题目的详细分析: #### 性别判定 为了防止因初始化不当而导致错误,建议使用布尔型变量来区分性别[^1]。具体实现上可以选择 `false` 表示男性,`true` 表示女性。这种设计能够有效避免后台测试数据中未出现的人物被误判为某一特定性别。 #### 关系图构建 通过输入的数据建立一个家庭成员之间的关系网络是非常重要的一步。通常情况下,可以采用 **邻接表** 的方式存储这些关系信息[^3]。这种方法不仅节省空间,而且便于后续进行深度优先搜索(DFS)或者广度优先搜索(BFS),从而快速找到某个人物五代以内的所有亲属。 #### 近亲检测算法 针对每一对情侣,需分别执行如下操作: 1. 对第一个人的所有直系和旁系亲属(限于五代以内)打上标记; 2. 接着遍历第二个人的亲属列表,一旦发现任何已标记的对象,则立即返回 “No”,表明二人存在近亲关系不可通婚; 3. 若完成上述过程仍未遇到重复标记的情况,则输出“Yes”。 这里提供一种基于 DFS 实现的方法作为参考: ```cpp #include <iostream> #include <vector> using namespace std; const int MAX_GEN = 5; // 定义最多追溯到第五代祖先 int n, m; vector<vector<int>> relations(100); // 假设节点编号从0开始 bool visited[100]; // 记录访问状态 bool marked[100]; // 标记第一人的亲属范围 void dfs(int u, int gen){ if(gen > MAX_GEN) return; // 超过五代停止扩展 if(!visited[u]){ visited[u] = true; for(auto v : relations[u]) { dfs(v, gen+1); } } } // 判断两个节点是否具有近亲关系 string checkRelation(int a, int b){ fill(visited, visited + 100, false); fill(marked, marked + 100, false); // 找a的所有五代内亲属并标记 dfs(a, 0); for(int i=0;i<100;i++) if(visited[i]) marked[i]=true; // 清除标志重新找b的亲属 fill(visited, visited + 100, false); bool conflict=false; dfs(b, 0); for(int i=0;i<100 && !conflict;i++) if(visited[i]&&marked[i]) conflict=true; return conflict ? "No" : "Yes"; } ``` 以上代码片段展示了如何利用递归函数 `dfs()` 来探索给定人物的后代直至达到规定的世代数为止,并据此决定两位潜在配偶之间能否合法联姻[^2]。 #### 特殊情况考虑 还需注意一些特殊情况下的处理逻辑,例如当某些个体并未出现在初始提供的家谱之中时该如何应对等问题。此时应将其视为无关联第三方对待即可。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值