Codeforces Round #230 (Div. 2) D - Tower of Hanoi

题目链接: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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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;
}


你可能感兴趣的:(Codeforces,Solutions)