Description
你对经典的hanoi塔问题一定已经很熟悉了。有三根柱子,n个大小不一的圆盘,要求大盘不能压在小盘上,初始时n个圆盘都在第一根柱子上,最少要多少步才能挪到最后一根柱子上?
现在我们来将hanoi塔扩展一下,由三根柱子扩展到四根柱子,其余规则不变。例如,3个圆盘,四根柱子A到D,初始时圆盘都A柱上,我们用五步就可以将圆盘都挪到D柱上:
第一步:将圆盘1从A挪到B;
第二步:将圆盘2从A挪到C;
第三步:将圆盘3从A挪到D;
第四步:将圆盘2从C挪到D;
第五步:将圆盘1从B挪到D。
你的任务是写一个程序求解四柱子hanoi塔问题最少要多少步可以解决。
Input
输入只有一行,为一个正整数n。(1<=n<=1000)
Output
输出为一个正整数,代表n盘四柱子hanoi塔问题最少要多少步可以解决。
Sample Input
3
Sample Output
5
Solution
设f[ i ]表示在四柱汉诺塔中,把i个盘子全部移到另一个盘子上的最小步数。
g[ i ]表示三柱汉诺塔中,把i个盘子全部移到另一个盘子上的最小步数。
则有g[ i ]=g[ i-1 ]*2+1,
意思是先把j个盘子在四柱的情况下移到一个柱上,这个柱就不能动了,剩下的i-j-1的盘子在三柱的情况下移到另一个盘子上。
然后将最后一个盘子用一步移到剩下那一个没有盘的柱上,再把其他两个柱上的所有盘子按照刚才移动的方法移到最后一个盘子所在的柱上即可。
答案只有15位,本来是不用高精度的,g[]可以只用存50几个即可。
时间复杂度O(n)。
Code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof a)
#define N 1005
#define M 100000
using namespace std;
I n,f[N][N],g[N][N],t[N],mn[N];
void R(I &x){
x=0;I w=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
x*=w;
}
I cmp(){
if(mn[0]>t[0]) return 1;
if(mn[0]<t[0]) return 0;
Fd(l,t[0],1){
if(t[l]<mn[l]) return 1;
if(t[l]>mn[l]) return 0;
}
return 0;
}
I main(){
freopen("hanoi.in","r",stdin);
freopen("hanoi.out","w",stdout);
R(n);
F(i,1,n){
g[i][0]=g[i-1][0];
F(j,1,g[i][0]) g[i][j]=g[i-1][j]*2;
g[i][1]++;
F(j,1,g[i][0]){
g[i][j+1]+=g[i][j]/M;
g[i][j]%=M;
}
while(g[i][g[i][0]+1]){
g[i][0]++;
g[i][g[i][0]+1]+=g[i][g[i][0]]/M;
g[i][g[i][0]]%=M;
}
// g[i]=g[i-1]*2+1;
mn[0]=1000;
// mn=1ll<<60;
F(j,0,i-1){
F(k,1,t[0]) t[k]=0;
t[0]=max(f[j][0],g[i-1-j][0]);
F(k,1,t[0]){
t[k]+=f[j][k]+g[i-1-j][k];
t[k+1]+=t[k]/M;
t[k]%=M;
}
while(t[t[0]+1]){
t[0]++;
t[t[0]+1]+=t[t[0]]/M;
t[t[0]]%=M;
}
//t[i]=f[j]+g[i-1-j];
//cmp
if(cmp()){
F(k,t[0]+1,mn[0]) mn[k]=0;
F(k,0,t[0]) mn[k]=t[k];
}
// mn=min(mn,f[j]+g[i-1-j]);
}
F(j,1,mn[0]) mn[j]*=2;
mn[1]++;
F(j,1,mn[0]){
mn[j+1]+=mn[j]/M;
mn[j]%=M;
}
while(mn[mn[0]+1]){
mn[0]++;
mn[mn[0]+1]+=mn[mn[0]]/M;
mn[mn[0]]%=M;
}
F(j,0,mn[0]) f[i][j]=mn[j];
F(j,0,mn[0]) mn[j]=0;
// f[i]=mn*2+1;
}
printf("%d",f[n][f[n][0]]);
Fd(i,f[n][0]-1,1) printf("%05d",f[n][i]);
return 0;
}