题解:洛谷 AT_abc461_b The Honest Woodcutters

【题目来源】

洛谷:AT_abc461_b [ABC461B] The Honest Woodcutters - 洛谷

【题目描述】

\(N\) 个樵夫编号为 \(1, 2, \dots, N\),每个人都有一把斧头。现在他们都把自己的斧头掉进了池塘。池塘里有 \(N\) 把斧头编号为 \(1, 2, \dots, N\) 被捞了上来。

每个樵夫 \(i\) 声称“我拥有第 \(A_i\) 号斧头”。而池塘女神则知道第 \(i\) 号斧头的真正主人是编号为 \(B_i\) 的樵夫。

请判断所有 \(N\) 个樵夫是否都讲了真话。

【输入】

输入通过标准输入给出,格式如下:

\(N~A_1~A_2~\dots~A_N~B_1~B_2~\dots~B_N\)

【输出】

如果所有 \(N\) 个樵夫都讲了真话,输出 Yes;否则输出 No

【输入样例】

3
3 1 2
2 3 1

【输出样例】

Yes

【核心思想】

  1. 问题分析:给定 \(N\) 个樵夫,每人声称拥有第 \(A_i\) 号斧头,而第 \(i\) 号斧头的真正主人是 \(B_i\)。需要判断所有樵夫是否都说真话,即对于每个樵夫 \(i\),他声称的斧头 \(A_i\) 的真正主人是否恰好是他自己。等价于验证:对于所有 \(i\),第 \(A_i\) 号斧头的真正主人 \(B_{A_i}\) 等于 \(i\)。或者换个角度:建立"斧头 \(\to\) 声称者"的映射和"斧头 \(\to\) 真正主人"的映射,验证两者是否完全一致。

  2. 算法选择

    • 映射构建与比对:将 \(A\) 数组转化为"斧头 \(x\) 被谁声称"的逆映射,然后与 \(B\) 数组逐位比较
  3. 关键步骤

    • 读入数据\(N\),数组 \(A[1..N]\)\(B[1..N]\)
    • 构建逆映射\(pos[A_i] = i\),表示第 \(A_i\) 号斧头被樵夫 \(i\) 声称
    • 逐位验证:对于 \(i\)\(1\)\(N\)
      • \(pos[i] \neq B_i\),输出 No 并结束
    • 输出结果:全部匹配则输出 Yes
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N)\),构建逆映射 \(O(N)\),验证 \(O(N)\)
    • 空间复杂度:\(O(N)\),逆映射数组
  5. 逆映射与一致性验证的核心思想

    • 双向验证的等价性:樵夫 \(i\) 说真话 \(\Leftrightarrow\) 他声称的斧头 \(A_i\) 的真正主人是他。即 \(B_{A_i} = i\)。代码通过构建逆映射 \(pos[x] = i\)(斧头 \(x\) 被樵夫 \(i\) 声称),然后验证 \(pos[i] = B_i\)(斧头 \(i\) 被樵夫 \(pos[i]\) 声称,而真正主人是 \(B_i\)),两者等价
    • 逆映射的巧妙构建:读入 \(A_i\) 时直接记录 \(a[A_i] = i\),将"谁声称哪把斧头"转化为"哪把斧头被谁声称",避免后续查找
    • 提前终止优化:一旦发现不匹配立即输出 No 并退出,最坏情况才需完整遍历
    • 排列性质利用\(A\)\(1\)\(N\) 的排列(每人声称不同的斧头),保证逆映射无冲突,无需处理重复
    • 适用于映射验证、排列比对、双向一致性检查类基础问题

【算法标签】

入门 #模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 105;  // 定义最大数量
int n;  // 元素数量
int a[N], b[N];  // 位置数组a,比较数组b
int main()  // 主函数
{
    cin >> n;  // 输入元素数量
    for (int i=1; i<=n; i++)  // 读取第一组数据
    {
        int x; cin >> x;  // 输入数字
        a[x] = i;  // 记录数字x在数组a中的位置
    }
    for (int i=1; i<=n; i++)  // 读取第二组数据
        cin >> b[i];  // 输入第二组数字
    for (int i=1; i<=n; i++)  // 比较两个数组
        if (a[i]!=b[i])  // 如果位置不匹配
        {
            cout << "No" << endl;  // 输出No
            return 0;  // 结束程序
        }
    cout << "Yes" << endl;  // 所有位置都匹配,输出Yes
    return 0;  // 程序正常结束
}

【运行结果】

3
3 1 2
2 3 1
Yes
posted @ 2026-08-26 10:12  团爸讲算法  阅读(5)  评论(0)    收藏  举报