//题目大意: 初始时候怀特双脚都在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]);
}
}
信息学竞赛DP专题(一)BNU8207舞蹈家怀特先生
最新推荐文章于 2021-12-01 19:47:51 发布