Prob.2[动态规划+递推+划归思想的应用]POJ 1958 Strange Towers Of Hanoi Upd:2020.3.1

传送门:http://poj.org/problem?id=1958

汉诺塔:https://www.cnblogs.com/antineutrino/p/3334540.html

问题引入:这个在标准的三塔问题上又加了一维,我们先考虑三个塔是怎么计算的?可以具体地分成三个步骤:

1.假设A塔上有n个盘子,将A塔上n-1个盘子转移到B塔上。

2.将A塔上剩余的一个盘子转移到C塔上。

3.将B塔上剩余的n-1个盘子转移到C塔上

因为后转移的盘子小,上面n-1个盘子都能落在上面,2之后的C柱可以看成空的柱子,于是1、3两步中的最小移动数相等。

设d[i]表示将i个盘子从A移动到C的方案数。B、C等效,于是d[n]=2*d[n-1]+1,两次1、3,最下方移动+1即可,线性递推不难。

由此可见,我们将n个盘子的移动,转化为了n-1个盘子的移动,进一步可以转化成n-2,n-3,n-4....3,2,1 这其实就是程序的递归/递推逻辑。

现在,让我们考虑四个柱子。一样是尝试着划归

首先,我们用四根柱子的方法,将A柱上的k个盘子转移到B柱上。然后由于B柱上所有的盘子都比A小,对于A柱剩余的n-k个盘子来说,B柱相当于没有。问题转化为了

三根柱子的问题!!于是我们用三根柱子的方法移动A柱上n-k个盘子,然后再用四根柱子的方法移动B上的k个盘子到D柱上,问题解决!

设f[i]表示i个盘子的方案数,d[i]同上。

由此,我们得到状态转移方程:

f[n]=min{2*f[k]+d[n-k]} k∈{1,2,.....n}

进一步,我们考虑m个柱子,n个盘子的情况。对于所有m个盘子,都可以先将其转化为m-1个盘子的情况,然后进行计算!上式依然成立,只不过f数组记录m个柱子的数据,d数组记录m-1个柱子的数据。

多么巧妙的递推!

AC代码:

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll d[13],f[120];
inline ll min(ll x,ll y)
{
return x<y?x:y;
}
int main()
{
memset(f,0x3f,sizeof(f));
f[1]=1;
d[1]=1;
for(int i=2;i<=13;i++)
d[i]=2*d[i-1]+1;
// printf("%d",d[n]);
for(int i=1;i<=12;i++)
for(int j=1;j<=i;j++)
f[i]=min(f[i],2*f[j]+d[i-j]);
for(int i=1;i<=12;i++)
printf("%lld\n",f[i]);
return 0;
}

猜你喜欢

转载自www.cnblogs.com/little-cute-hjr/p/12388762.html