sgu-202 The Towers of Hanoi Revisited

题目大意:

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

f(n,k)为在有k个柱子时,移动n个圆盘到另一柱子上需要的步数,则:

对于任何移动方法,必定会先将 m(1\le m\le n-1)个圆盘移动到一个中间柱子上,再将第n到第n-m个圆盘通过剩下的k-1个柱子移到目标柱子上,最后将m个在中间柱子上的圆盘移动到目标柱子上。这样所需的操作步数为 2f(m,k)+f(n-m,k-1)进行 最优化 ,易得:f(n,k)=\mathrm{min}_{m\in [1,n-1]}\; (2f(m,k)+f(n-m,k-1))  
那么如何输出呢?
还是很简单的,我们记录一个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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值