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

来源:互联网 发布:linux删除进程命令 编辑:程序博客网 时间:2024/05/22 05:01

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

可以发现,当移动第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;}


原创粉丝点击