POj 3601 Tower of Hanoi 汉诺塔(贪心)

博客内容介绍了汉诺塔问题并加入了新的条件——盘子可以有相同的。通过分析,得出不考虑顺序的移动次数公式`dp1[i]=dp1[i-1]*2+num[i]`和考虑顺序的移动次数公式`dp2[i]=2*dp1[i-1]+2*num[i]+dp2[i-1]`。最后,给出了问题的解决方案,重点在于如何保持盘子顺序不变。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:汉诺塔问题,不过其中加了一个条件,就是盘子可以有相同的

可以发现,当移动第i 种盘子时&& num[i]>=2得到的是逆序的,但是题目要求不能改变顺序,所以必须处理

1.先考虑不按顺序的情况为 dp1[i]=dp1[i-1]*2+num[i]  ,num[i]为相同盘子的个数

公式得来:如果从A到C轴,借助B轴,i种盘子,要先把i - 1种移动到 B, 需要dp1[i - 1],然后把第i种移动到C,需要num[i],然后再把i - 1种从B移动到C,需要dp1[i - 1]
所以得到dp1[i]=dp1[i-1]*2+num[i] .

2.考虑按顺序的情况为 dp2[i]=2*dp1[i-1]+2*num[i]+dp2[i-1]

公式得来:把num[1] - 1个移动到辅助轴,这时这num[1] - 1个盘子的顺序颠倒了,然后把第num[1]中最后一个移动到目标轴,然后把辅助轴上的移动回来,再次颠倒,恢复顺序,得到dp2[1] = 2 * (num[1] - 1) +1。
对于dp2[i],
如果x[i] == 1,那么第i种就不需要考虑顺序(只有一种),所以dp2[i] = dp1[i]
否则,第i种要调动2次,保证顺序不变。
还是从A到C轴,借助B轴,i种盘子
把i - 1种不考虑顺序移到C,需要dp1[i - 1].
把第i种从A移动到B,需要num[i](颠倒顺序),
把i - 1种不考虑顺序移到A(腾出C),需要dp1[i - 1].
把第i种从B移动到C,需要num[i](顺序恢复)
把i - 1种考虑顺序移到C,需要dp2[i - 1].
所以有dp2[i] = 2 * dp1[i - 1] +2 * num[i] +dp2[i - 1]
最后答案是dp2[n].

代码:

#include <stdio.h>
#include <cstring>
using namespace std;
int dp1[105];
int dp2[105];
int num[105];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        scanf("%d",&num[i]);
        dp1[1]=num[1];//dp1不考虑顺序
        for(int i=2;i<=n;i++)
        dp1[i]=(2*dp1[i-1]+num[i])%m;
        dp2[1]=2*(num[1]-1)+1;//考虑顺序
        for(int i=2;i<=n;i++)
        {
            if(num[i]==1)
            dp2[i]=dp1[i]%m;
            else
            dp2[i]=(2*dp1[i-1]+2*num[i]+dp2[i-1])%m;
        }
        printf("%d\n",dp2[n]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值