Tower of Hanoi CodeForces - 392B(dfs——记忆化搜索)

Tower of Hanoi

 题目链接:CodeForces - 392B

题意:在经典的汉诺塔的基础上进行了改造,不是问最少移动次数,而是问最少移动代价;从i柱移动到j柱的代价是t[i][j],求最少移动代价;

思路:先回顾一下汉诺塔,

当有n个盘子时最少需要移动(2^n)-1次;路径打印如下:

#include <bits/stdc++.h>
using namespace std;
void dfs(int n, int from, int by, int to){
	if(n==1){
		printf("%d->%d\n", from, to);
		return;
	}
	dfs(n-1, from, to, by);
	printf("%d->%d\n", from, to);
	dfs(n-1, by, from, to);
}
int main(){
	int n;
	while(cin >> n){
		dfs(n, 1, 2, 3);
	}	
	return 0;
}

当只有一个盘子时,直接将盘子移动到3号柱,图一;

有两个盘子时,先将小盘移到2号柱,再将大盘移到3号柱,再将小盘移动到3号柱, 图二;

                                              

                      图一                                                                              图二

当盘子个数为n时,把n-1看作是一个整体,把n-1个先挪到二号柱,再把第n个挪到3号柱,再把n-1挪到3号柱;这其实就是一个递归的过程;

------------------------------------------------------------------------华丽的分割线-------------------------------------------------------------------------------

现在再来看看这道题,汉诺塔的最小代价;

其实汉诺塔无论怎么挪,都只有两种方式:

一:同找最少次数相同;先把n-1个盘子经过3号柱的辅助挪到2号柱,再把第n个盘子挪到3号柱, 最后把前n-1个盘子经由1号柱的辅助挪到3号柱;此时dfs(n, from, by, to)=dfs(n-1, from, to, by)+t[from][to]+dfs(n-1, by, from, to);

二:先把n-1个盘子经由2号柱的辅助挪到3号柱,再把第n个盘子挪到2号柱,再把前n-1个盘子从3号柱经由2号柱的辅助挪到1号柱,再把第n个盘子从2号柱挪到3号柱,最后把前n-1个盘子从1号柱经由2号柱的辅助挪到3号柱;此时dfs(n, from, by, to)=dfs(n-1, from, by, to)+t[from][by]+dfs(n-1, to, by, from)+t[by][to]+dfs(n-1, from, by, to);

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t[4][4], dp[50][4][4][4];
ll dfs(int n, int from, int by, int to){
	if(n==1) return min(t[from][to], t[from][by]+t[by][to]);
	if(dp[n][from][by][to]!=-1) return dp[n][from][by][to];//如果此状态已经有结果,就直接返回,优化时间;
	ll temp1, temp2;
	temp1=dfs(n-1, from, to, by)+t[from][to]+dfs(n-1, by, from, to);
	temp2=dfs(n-1, from, by, to)+t[from][by]+dfs(n-1, to, by, from)+t[by][to]+dfs(n-1, from, by, to);
	dp[n][from][by][to]=min(temp1, temp2);
	return dp[n][from][by][to];
}
int main(){
	for(int i=1; i<=3; i++){
		for(int j=1; j<=3; j++){
			scanf("%lld", &t[i][j]);
		}
	}
	int n;
	scanf("%d", &n);
	memset(dp, -1, sizeof(dp));
	printf("%lld\n", dfs(n, 1, 2, 3));
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值