题目链接:http://codeforces.com/contest/393/problem/D
大致题意:汉罗塔问题的变形,给三个柱子,对于每一次移动都会给出一个消耗cost,问将所有盘子从1号柱子移到3号柱子的最小花费。
思路:dp思路,dp[i][j][n]表示将n个盘子从第i号柱子移到第j号柱子的最小花费,在进行状态转移的时候还是很有技巧的。
我们将柱子用1,2,3来标号,假如我现在要将1号柱子的n个盘子移道3号柱子上,传统的递归思路是先将n-1个盘子移到2号柱子,再将最后一个盘子移到第3,再将2号盘子的n-1个盘子移到三号柱子上,所以我们得到了第一种状态转移的方法:
(1)dp[1][3][n]=dp[1][2][n-1]+cost[1][3]+dp[2][3][n-1]
我们还可以将前n-1个盘子移到3号柱子上,再将1号柱子上最后一个盘子移到2号柱子上,再将前n-1个盘子移到1号柱子上,再将最后一个盘子移到3号柱子上,再将n-1个盘子移到3号柱子上,所以我们得到了第二种状态转移的方法:
(2) dp[1][3][n]=dp[1][3][n-1]+cost[1][2]+dp[3][1][n-1]+cost[2][3]+dp[1][3][n-1]
我们还能够得到第三种转移的方法:
(3) dp[1][3][n]=dp[1][3][n-1]+dp[3][2][n-1]+cost[1][3]+dp[2][3][n-1]
但是有效的只有上面的(1)(2)两种,我们对比发现
1. (1),(2)在最基础的选择上是有差别的(cost[1][3],cost[1][2]+cost[2][3]),而(1),(3)在最基础的决策上是相同的。
2. (3)>=(1)的,因为dp[1][2][n-1] 已经代表了从1到2的最小值,(3)中的间接从1到2的方法是不可能比它小的。
所以由此也能引起我们对dp类问题的一些思考:
1.在做决策的时候要从最基础的决策方面思考差异来列dp方程。
2.充分利用子问题的解的最优性质~~。
code:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <assert.h>
using namespace std;
#define SIZE 1000
#define INF 2147483647
typedef long long LL;
LL dp[SIZE][3][3];
int cost[3][3];
LL Min(LL a,LL b)
{
return a>b? b:a;
}
int main()
{
for(int i=0;i<3;i++) for(int j=0;j<3;j++) scanf("%d",&cost[i][j]);
int N;
scanf("%d",&N);
for(int i=0;i<3;i++) for(int j=0;j<3;j++) dp[0][i][j]=0;
for(int i=1;i<=N;i++){
for(int a=0;a<3;a++){
for(int c=0;c<3;c++){
int b=3-a-c;
if (a==c) dp[i][a][c]=0;
else dp[i][a][c]=Min((LL)(dp[i-1][a][b]+cost[a][c]+dp[i-1][b][c]),
(LL)(2*dp[i-1][a][c]+cost[a][b]+dp[i-1][c][a]+cost[b][c]));
}
}
}
printf("%lld\n",dp[N][0][2]);
return 0;
}