OneCoder Avatar
OneCodercoderli.com · 955 篇博文
四级

C++ 算法考级专栏

真题分析、矩阵探测、递归回溯与基础语法

🎨 视觉封面

【顺时针单向递归与双状态递推】GESP四级 / CSP-J 题解:luogu-B4579 [GESP202609 四级] 新汉诺塔

📅 2026-09-15·✍️ OneCoder·计算中...·⏱️ 6 分钟
#GESP#C++#GESP四级#CSP-J#递归#递推#分治#真题#2026年9月#GESP202609

CCF GESP 2026年9月认证(第十五次认证)C++ 四级试题,洛谷 B4579。本题严格遵循 CCF GESP 官方大纲规范,重点考察顺时针单向递归与双状态递推。题目逻辑严密,模型典型,是深入理解与掌握信奥核心考点的经典范例。

B4579 [luogu-B4579 [GESP202609 四级] 新汉诺塔]

🔗 洛谷原题传送门B4579

题目要求

题目描述

经典汉诺塔有 A、B、C 三根柱子,初始 A 上有从小到大排列的 nn 个圆盘,目标是移到 C。 小杨添加了新规则:每一次移动,圆盘只能顺时针移动,即只能从 ABA \to BBCB \to CCAC \to A;其它移动是不允许的。 在新规则下,给定圆盘数量 nn,求将 nn 个圆盘从 A 移动到 C 所需的最少移动步数。

输入格式

输入一个正整数 nn,表示圆盘的数量。

输出格式

输出一个整数,表示最少移动步数。

输入输出样例

样例输入 #1
TEXT
2
样例输出 #1
TEXT
7

说明/提示

n20n \le 20。对于 n=3n=3,输出为 21。


题目分析与解题思路

  1. 双状态分治递推定义: 由于只能顺时针移动,移动 1 步与移动 2 步性质不同,需要引入互相依赖的双状态:
    • f(n)f(n) 为将 nn 个盘顺时针移动 1 根柱子(如 ABA \to B)的最少步数;
    • g(n)g(n) 为将 nn 个盘顺时针移动 2 根柱子(如 ACA \to C)的最少步数。
  2. 初始状态(n=1n=1
    • 11 个盘 ABA \to B:直接移 11 步,故 f(1)=1f(1) = 1
    • 11 个盘 ACA \to C:必须经 ABCA \to B \to C,共 22 步,故 g(1)=2g(1) = 2
  3. 状态转移关系
    • f(n)f(n)ABA \to B
      1. n1n-1 个盘 ACA \to C(顺移 2 步):g(n1)g(n-1) 步;
      2. nn 个盘 ABA \to B(顺移 1 步):11 步;
      3. n1n-1 个盘 CBC \to B(顺移 2 步):g(n1)g(n-1) 步。 即:f(n)=2g(n1)+1f(n) = 2g(n-1) + 1
    • g(n)g(n)ACA \to C
      1. n1n-1 个盘 ACA \to C(顺移 2 步):g(n1)g(n-1) 步;
      2. nn 个盘 ABA \to B(顺移 1 步):11 步;
      3. n1n-1 个盘 CAC \to A(顺移 1 步):f(n1)f(n-1) 步;
      4. nn 个盘 BCB \to C(顺移 1 步):11 步;
      5. n1n-1 个盘 ACA \to C(顺移 2 步):g(n1)g(n-1) 步。 即:g(n)=2g(n1)+f(n1)+2g(n) = 2g(n-1) + f(n-1) + 2
  4. 数据范围n20n \le 20g(20)g(20) 结果在 long long 范围内,时间复杂度 O(n)\mathcal{O}(n)

完整参考代码 (C++11)

CPP
/**
 * Problem: luogu-B4579
 * Standard: C++11 (CCF GESP 官方大纲规范)
 * Author: OneCoder
 */

#include <iostream>
#include <vector>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n) || n <= 0) {
        return 0;
    }

    // f[i]: 顺时针跨 1 根柱子(A->B)
    // g[i]: 顺时针跨 2 根柱子(A->C)
    vector<long long> f(n + 1, 0);
    vector<long long> g(n + 1, 0);

    f[1] = 1;
    g[1] = 2;

    for (int i = 2; i <= n; ++i) {
        f[i] = 2 * g[i - 1] + 1;
        g[i] = 2 * g[i - 1] + f[i - 1] + 2;
    }

    cout << g[n] << "\n";

    return 0;
}

考点归纳与备考建议

  1. 考纲匹配度:严格对标 CCF GESP 四级考纲重点,绝不超纲,注重基础算法与逻辑建模规范;
  2. 规范防范:所有代码严格以 C++11 标准编译运行,针对整数溢出、边界判断、空状态均做了详尽严整的防御性处理。
💡 OneCoder 资源指引

所有代码开源上传至 GitHub:yummy-code 仓库 · GESP 专题站:GESP WIKI

🤝 技术交流与答疑

欢迎加入:C++ GESP/CSP 考级答疑群(688906745)Java/Python交流群(982860385),点击可直接加群。

📚

猜你想读 · 相关文章推荐

OneCoder

OneCoder (lihongzheshuai)

一个中年人的自留地,记录学习 C++、GESP/NOI、Java、Python 与算法架构的心得体会。本站唯一网址:coderli.com

💬 读者留言与交流

0 条讨论
✨ 支持 Markdown 语法格式
还没有留言,快来成为第一个讨论者吧!