Codeforce 392B Tower of Hanoi 区间dp

时间:2014-02-21 13:35:19   收藏:0   阅读:391

题目链接:http://codeforces.com/contest/393/problem/D

给定一个3*3的矩阵 [i,j] 表示把一个盘子从第i根柱子移到第j跟柱子的花费

下面一行n表示一共有n个盘子在1号柱子

问:全部都移动到3号柱子的最小花费

思路:

显然是一个区间dp

dp[num][i][j] 表示把num个盘子从 i->j 需要的最小花费

 

注意dfs是表示在上方的盘子移动的最小花费

在底部的那个盘子移动是 矩阵的花费

 

inf一定要足够大 1e18

 

#include<stdio.h>
#include<queue>
#include<iostream>
#include<string.h>
#include<math.h>
#include<set>
using namespace std;
#define inf 1000000000000000000
#define ll __int64
ll n;
ll map[3][3];
ll dp[42][3][3];
ll dfs(ll num, ll s, ll t){
	if(dp[num][s][t]<inf)return dp[num][s][t];
	ll ans = inf, i;
	ll z = 6/((1+s)*(1+t))-1;
	ll sz = min(dfs(num-1,s,z), dfs(num-1,s,t)+dfs(num-1,t,z));//s-z
	ll zt = min(dfs(num-1,z,t), dfs(num-1,z,s)+dfs(num-1,s,t));//z-t
	ll st = min(dfs(num-1,s,t), dfs(num-1,s,z)+dfs(num-1,z,t));//s-t
	ll ts = min(dfs(num-1,t,s), dfs(num-1,t,z)+dfs(num-1,z,s));//t-s

	ans = min(ans, map[s][t]+sz+zt);
	ans = min(ans, st+map[s][z]+ts+map[z][t]+st);
	return dp[num][s][t] = ans;
}
int main()
{
	ll i,j,n;

	while(~scanf("%I64d",&map[0][0]))
	{
		scanf("%I64d %I64d",&map[0][1],&map[0][2]);
		for(i=1;i<=2;i++)for(j=0;j<=2;j++)scanf("%I64d",&map[i][j]);
		scanf("%I64d",&n);
		for(i=2;i<=n;i++)	for(j=0;j<3;j++)	for(ll k = 0; k < 3; k++)	dp[i][j][k] = inf;

		memset(dp[0], 0, sizeof(dp[0]));
		for(i=0;i<=2;i++)for(j=0;j<=2;j++)
			dp[1][i][j] = min(map[i][j],map[i][6/((1+i)*(1+j))-1]+map[6/((1+i)*(1+j))-1][j]);

		for(i=1;i<=n;i++)	for(j=0;j<3;j++)	dp[i][j][j] = 0;
		printf("%I64d\n", dfs(n,0,2));
	}
	return 0;
}
/*
0 1 1
1 0 1
1 1 0
3
0 2 2
1 0 100
1 2 0
3
0 2 1
1 0 100
1 2 0
5
0 1 10
1 0 1
10 1 0
1

*/


 

原文:http://blog.csdn.net/acmmmm/article/details/19572301

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!