PAT 天梯赛 L3-008. 喊山 【BFS】

题目链接

https://www.patest.cn/contests/gplt/L3-008

思路
因为 每个山头 最多有两个 能听到它的 临近山头
那么 我们就可以 给每个 山头 都 分配 最多两个子儿子
然后 再从儿子 往下找
一层一层往下找 如果找的元素 之前已经出现过 这个 就不压入 队列
直到最后 队列为空 输出当层 编号最小的那个

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>

#define CLR(a) memset(a, 0, sizeof(a))

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-3;

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

int ans;

queue <int> opt;

map <int, int> q, vis;

struct Node
{
    int l, r;
}w[maxn];

void bfs(int cur)
{
    int len = opt.size();
    int Min = INF;
    while (len--)
    {
        int num = opt.front();
        opt.pop();
        if (num < Min)
            Min = num;
        if (vis[w[num].l] == 0)
        {
            opt.push(w[num].l);
            vis[w[num].l] = 1;
        }
        if (vis[w[num].r] == 0)
        {
            opt.push(w[num].r);
            vis[w[num].r] = 1;
        }
    }
    if (opt.empty())
    {
        ans = Min;
        return;
    }
    else
        bfs(cur + 1);
}

int main()
{
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    int a, b;
    for (int i = 0; i < m; i++)
    {
        scanf("%d%d", &a, &b);
        q[a] = 1;
        q[b] = 1;
        if (w[a].l)
            w[a].r = b;
        else
            w[a].l = b;
        if (w[b].l)
            w[b].r = a;
        else
            w[b].l = a;
    }
    for (int i = 0; i < k; i++)
    {
        scanf("%d", &a);
        if (q[a] == 0)
            printf("0\n");
        else
        {
            vis.clear();
            vis[0] = 1;
            while (!opt.empty())
                opt.pop();
            if (w[a].l != 0)
                opt.push(w[a].l);
            if (w[a].r != 0)
                opt.push(w[a].r);
            vis[w[a].l] = 1;
            vis[w[a].r] = 1;
            vis[a] = 1;
            bfs(1);
            printf("%d\n", ans);
        }
    }
}
### 天梯赛 L2-007 题目解析与解法 #### 问题描述 天梯赛 L2-007 的题目通常涉及较为复杂的算法设计和数据结构应用。虽然具体的题目可能因年度不同而有所变化,但从引用的内容来看,可以推测此题属于中级难度 (L2),主要考察参赛者的编程能力和逻辑思维能力。 以下是基于一般性的假设对该类问题的分析以及解决方案: --- #### 数据输入说明 根据提供的背景信息[^2],假定本题的数据输入形式如下: - 输入的第一行为两个正整数 \( N \) 和 \( M \),分别代表总人数和照片数量。 - 接下来的 \( M \) 行,每行描述一张照片中的人员编号及其关系。 - 最后一行提供了一对异性情侣的编号 \( A \) 和 \( B \)。 目标可能是判断这对情侣是否可以通过某些条件(例如共同的照片或社交网络)建立联系。 --- #### 解决方案思路 ##### 方法一:图论建模 + 广度优先搜索 (BFS) 如果问题是关于人际关系网的连通性,则可将其抽象为无向图模型: - **节点**:每个人对应一个节点。 - **边**:当两个人出现在同一张照片中时,在他们之间创建一条无权边。 通过广度优先搜索 (BFS) 或深度优先搜索 (DFS),可以从起点 \( |A| \) 开始遍历整个图,检查终点 \( |B| \) 是否可达。 实现代码如下: ```python from collections import defaultdict, deque def solve(): # 初始化读取输入 n, m = map(int, input().split()) graph = defaultdict(list) # 构造图 for _ in range(m): data = list(map(int, input().split())) k = data[0] people = data[1:] for i in range(k): for j in range(i + 1, k): u, v = abs(people[i]), abs(people[j]) graph[u].append(v) graph[v].append(u) a, b = map(abs, map(int, input().split())) # BFS 实现 visited = set() queue = deque([a]) while queue: current = queue.popleft() if current == b: print("Yes") # 可达 return if current not in visited: visited.add(current) for neighbor in graph[current]: if neighbor not in visited: queue.append(neighbor) print("No") # 不可达 ``` 上述方法的时间复杂度为 \( O(M + N) \)[^3],适用于大规模数据处理场景。 --- ##### 方法二:并查集 (Union-Find) 另一种高效的方法是利用并查集来解决集合划分问题。具体步骤如下: 1. 创建初始状态下的独立集合,每个节点自成一体。 2. 对于每张照片中的所有成员,执行 `union` 操作以合并它们所属的集合。 3. 查询 \( A \) 和 \( B \) 所属集合是否相同即可得出结论。 代码示例如下: ```python class UnionFind: def __init__(self, size): self.parent = list(range(size)) def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) # 路径压缩 return self.parent[x] def union(self, x, y): rootX = self.find(x) rootY = self.find(y) if rootX != rootY: self.parent[rootY] = rootX def solve_union_find(): n, m = map(int, input().split()) uf = UnionFind(n) for _ in range(m): data = list(map(int, input().split())) k = data[0] people = data[1:] base = None for person in people: idx = abs(person) if base is None: base = idx else: uf.union(base, idx) a, b = map(abs, map(int, input().split())) if uf.find(a) == uf.find(b): print("Yes") else: print("No") ``` 这种方法的优势在于其时间复杂度接近常数级别 \( O(\alpha(N)) \)[^4],其中 \( \alpha \) 是反阿克曼函数,增长极其缓慢。 --- #### 结果验证 无论采用哪种方法,最终都需要确保程序能够正确处理边界情况,例如: - 当 \( A \) 和 \( B \) 属于同一个集合时返回 “Yes”; - 否则返回 “No”。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值