题目大意:
hanoi问题
输入给你两个数n,m,表示有n个盘子,m个柱子,问最少需要多少步使得n个盘子从柱子1->m,并且输出方案
输出方法move i from s to t 表式移动盘子i从s放到t上,如果t上原本有盘子j,那么输出move i from s to t atop j
解题思路:
首先我们用dp求出最短的步数
dp思路摘自http://www.cnblogs.com/hzf-sbit/p/3903573.html
令为在有k个柱子时,移动n个圆盘到另一柱子上需要的步数,则:
-
- 对于任何移动方法,必定会先将 个圆盘移动到一个中间柱子上,再将第n到第n-m个圆盘通过剩下的k-1个柱子移到目标柱子上,最后将m个在中间柱子上的圆盘移动到目标柱子上。这样所需的操作步数为 。 进行 最优化 ,易得:
- 那么如何输出呢?
- 还是很简单的,我们记录一个father[a][b]表示当有a个盘子,b个柱子时当是f(a,b)最优的那个m值,然后递归求解就行了
- 具体请看我的程序
-
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> using namespace std; int n,m; int f[70][70]={{0}}; int father[70][70]={{0}}; int num[70]={0}; int hanoi[70][70]={{0}}; void prt(int s,int t,int a,int b) { if(a==1) { printf("move %d from %d to %d ",hanoi[s][num[s]],s,t); if(num[t]!=0) printf("atop %d",hanoi[t][num[t]]); puts(""); hanoi[t][++num[t]]=hanoi[s][num[s]--]; return; } for(int i=1;i<=m;i++) if(i!=s && i!=t) { if(hanoi[i][num[i]]>hanoi[s][num[s]-father[a][b]+1]) { prt(s,i,father[a][b],b); prt(s,t,a-father[a][b],b-1); prt(i,t,father[a][b],b); return; } } return; } int main() { cin>>n>>m; for(int i=0;i<70;i++) for(int j=0;j<70;j++) f[i][j]=7e8; for(register int i=1;i<=m;i++) f[1][i]=1; for(register int i=2;i<=n;i++) for(register int j=3;j<=m;j++) { for(register int p=1;p<i;p++) { int tmp=(f[p][j]<<1)+f[i-p][j-1]; if(f[i][j]>tmp) { f[i][j]=tmp; father[i][j]=p; } } } cout<<f[n][m]<<endl; for(int i=n;i>=1;i--) hanoi[1][++num[1]]=i; for(int i=1;i<=m;i++) hanoi[i][0]=7e8; prt(1,m,n,m); return 0; }