信息学竞赛DP专题(一)BNU8207舞蹈家怀特先生

//题目大意: 初始时候怀特双脚都在0的位置.之后每次出现一个1-4中的一个数.1=UP.2=right.3=down.4=left.
//          0到其他位置消耗2体力.其他时候.在原地跳消耗1体力..跳到相邻位置消耗3体力.跳到相对位置消耗4体力.
//          给定一个跳舞的序列步伐.问最后消耗的体力最少是多少.
//解题思路: 用DP[i][j][k] 表示在第i次的时候位置在j和k的时候选择策略的最优值.那么转移方程是
//          DP[i][j][k] = min(dp[i+1][j][a[i]] + effor(a[i],k) , dp[i+1][a[i]][k] + effor(a[i],j));
//          这是一个从后面往前比较简单的题目..由于双脚在每个阶段的状态只有4*4十六种情况.同时.第i次策略的
//          代价是和当前双脚所在的位置有关的..所以选择双脚所在位置作为状态是很好的..
//题目连接:http://219.224.30.70/bnuoj/problem_show.php?pid=8207
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<math.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
int effor(int x , int y)
{
    if(x == y)return 1;
    if(x == 0 || y == 0)return 2;
    if(x == 2 && (y == 1 || y == 3) ) return 3;
    if(y == 2 && (x == 1 || x == 3) ) return 3;
    if(x == 1 && (y == 4 || y == 2) ) return 3;
    if(y == 1 && (x == 4 || x == 2) ) return 3;
    if(x == 3 && (y == 2 || y == 4) ) return 3;
    if(y == 3 && (x == 2 || x == 4) ) return 3;
    if(x == 4 && (y == 1 || y == 3) ) return 3;
    if(y == 4 && (x == 1 || x == 3) ) return 3;
    return 4;
}
const int mn = 111111;
int dp[mn][5][5],test[mn];
int main()
{
   // freopen("in1.txt","r",stdin);
   // freopen("ou1.txt","w",stdout);
    int n;
    while(scanf("%d",&test[1]) && test[1] != 0)
    {
        n = 1;
        for(int i = 2 ;  ; i++)
        {
            scanf("%d",&test[i]);
            if(test[i] == 0)break;
            n = i;
        }
        memset(dp,10000,sizeof(dp));
        //0.中间..1.up..2 right . 3 down  4 left
//        if(n > 1)
//        {
//            dp[n+1][test[n-1]][test[n]] = 0;
//            dp[n+1][test[n]][test[n-1]] = 0;
//        }
        for(int i = 0 ; i <= 4 ; i++)
        {
            dp[n+1][test[n]][i] = 0;
            dp[n+1][i][test[n]] = 0;
        }
        for(int i = n ; i >= 1 ; i--)
        {
            for(int j = 0 ; j <= 4 ; j++)
            {
                for(int k = 0 ; k <= 4 ; k++)
                {
                    dp[i][j][k] = min(dp[i+1][j][test[i]] + effor(k,test[i]) , dp[i+1][test[i]][k] + effor(j,test[i]));
                  //  printf("%d   %d   %d  %d\n",i,j,k,dp[i][j][k]);
                //  printf("%d  %d  %d  %d\n",i,j,k,dp[i][j][k]);
                 // if(dp[i][j][k] < 0)while(1);
                }
            }

        }
        printf("%d\n",dp[1][0][0]);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值