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

Tower of Hanoi

 题目链接:CodeForces - 392B

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

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

Tower of Hanoi CodeForces - 392B(dfs——记忆化搜索)_第1张图片

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

#include 
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号柱, 图二;

Tower of Hanoi CodeForces - 392B(dfs——记忆化搜索)_第2张图片                                              Tower of Hanoi CodeForces - 392B(dfs——记忆化搜索)_第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 
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;
}

 

你可能感兴趣的:(递归,怒刷DP)