ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF392B Tower of Hanoi

2020-03-12 23:02:06  阅读:289  来源: 互联网

标签:int Hanoi 花费 long ++ CF392B 盘子 Tower Rightarrow


题目链接

Description

三塔汉诺塔问题,给一个 \(3 \times 3\) 的矩阵 \(t\),\(t_{i, j}\) 表示从 \(i\) 塔移动一个盘子到 \(j\) 塔的花费。

初始状态 \(n\) 个盘子都在第一个盘子,要求将所有的移到第三个盘子,求最小花费。

Solution

显然可以间接移动,花费有可能更优,先用 Floyd 算法算出从 \(i\) 间接 / 直接移动到 \(j\) 的最小花费,设 \(d_{i,j}\) 表示从 \(i\) 到 \(j\) 的最小花费。

显然无后效性,考虑 \(dp\)。

状态设计

设 \(f_{i,a,b}\) 表示将 \(i\) 个盘子从 \(a\) 移动到 \(b\) 的最小花费。

初始状态

\(f_{1, a, b} = d_{a,b}\) 其余为正无穷

状态转移

不妨设另外一个盘子为 \(c\)。

先把 \(n\) 个盘子看做两个整体:第 \(n\) 个盘子和 \(n - 1\) 个盘子,这样可以 DP 了。

通过观察发现有两个可能成为最优的转移方式:

  • 将 \(n - 1\) 个盘子 \(a \Rightarrow c\),第 \(n\) 个盘子 \(a \Rightarrow b\),然后再把 \(n - 1\) 个盘子 \(c \Rightarrow b\)。
  • \(n - 1\) 个盘子 \(a \Rightarrow b\),第 \(n\) 个盘子 \(a \Rightarrow c\),\(n - 1\) 个盘子 \(b \Rightarrow a\),第 \(n\) 个盘子 \(c \Rightarrow b\),\(n - 1\) 个盘子 \(a \Rightarrow b\)。

其他的转移一定是这两种 + 反复横跳形成的。

将上面的方式翻译一下,即:

  • \(f_{i, a, b} \gets f_{i - 1, a,c} + t_{a,b} + f_{i - 1, c, b}\)

  • \(f_{i, a, b} \gets f_{i - 1, a,b} + t_{a,c} + f_{i - 1, b, a} + t_{c,b} + f_{i - 1, a, b}\)

值得注意的是这里不能用 \(d\),因为其他盘子不是空的,不能作为间接量。

时间复杂度

\(O(N)\)

Tips

注意开 long long !

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 45;

typedef long long LL;

int t[3][3], g[3][3], n;
LL f[N][3][3];


int main() {
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++) scanf("%d", &t[i][j]), g[i][j] = t[i][j];
    scanf("%d", &n);
    for (int k = 0; k < 3; k++)
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                t[i][j] = min(t[i][j], t[i][k] + t[k][j]);
    memset(f, 0x3f, sizeof f);
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            f[1][i][j] = t[i][j];

    for (int i = 2; i <= n; i++) {
        for (int a = 0; a < 3; a++) {
            for (int b = 0; b < 3; b++) {
                if (a == b) continue;
                int c = 3 - a - b;
                f[i][a][b] = min(f[i - 1][a][c] + g[a][b] + f[i - 1][c][b], f[i - 1][a][b] + g[a][c] + f[i - 1][b][a] + g[c][b] + f[i - 1][a][b]);
            }
        }
    }
    printf("%lld\n", f[n][0][2]);
    return 0;
}

标签:int,Hanoi,花费,long,++,CF392B,盘子,Tower,Rightarrow
来源: https://www.cnblogs.com/dmoransky/p/12483477.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有