题意
跳舞机,需要按给出的方向序列踩箭头。一个箭头可以由左脚踩,也可以由右脚踩。正常情况下,不能出现左脚在右,右脚在左的情况。但是,可以出现,左脚在右,右脚在上或在下的情况,此时,在左脚移动前,右脚不能移动。当出现箭头时,即便你的脚在这个箭头上,也需要踩一下。如果这只脚上个时间单位没有任何动作,则消耗1单位能量。如果这只脚上个时间单位没有移动,则消耗3单位能量。如果这只脚上个时间单位移动到相邻箭头,消耗5单位能量。如果这只脚上个单位移动到相对箭头,消耗7单位能量。求如何踩所消耗的能量最少。
题解
多阶段DP。用dp[i][a][b][s]代表已经踩了i个箭头,左脚在a箭头上,右脚在b箭头上,上一个阶段移动的脚为s(0代表没有脚移动,1代表左脚移动,2代表右脚移动)。如果下一步是’.’则有三种决策方案,左脚移动到另一个箭头,右脚移动到另一个箭头,不移动。如果下一步是四个箭头之一,则有两种决策方案,左脚移动到该箭头,右脚移动到该箭头。
注意事项
本题条件判断比较多,特别要注意判断是否相等的等号(==)不要写成=。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[100][4][4][3];
const int LEFT=1,RIGHT=2;
char foot[]=".LR";
char chc[256];
struct Node{
int f,t;
};
Node action[100][4][4][3];
int getAdd(int a,int b){
if(a==b)
return 3;
else if(a+b==3)
return 7;
else
return 5;
}
int update(int i,int a,int b,int s,int t,int f,int &ta,int &tb){
ta=a,tb=b;
if(f==LEFT){
ta=t;
}else if(f==RIGHT){
tb=t;
}
if(ta==tb){
return -1;
}else if(ta==RIGHT&&tb==LEFT){
return -1;
}else if(b==LEFT&&ta!=a){
return -1;
}else if(a==RIGHT&&tb!=b){
return -1;
}
if(f==0){
return 0;
}else if(f!=s){
return 1;
}else{
if(f==LEFT){
return getAdd(a,ta);
}else{
return getAdd(b,tb);
}
}
}
void energy(int i,int a,int b,int s,int t,int f){
int ta,tb;
int v=update(i,a,b,s,t,f,ta,tb);
if(v<0)
return ;
int& ans=dp[i][a][b][s];
if(ans>v+dp[i+1][ta][tb][f]){
ans=v+dp[i+1][ta][tb][f];
action[i][a][b][s]=(Node){f,t};
}
}
int main()
{
//freopen("d://input.txt","r",stdin);
//freopen("d://output.txt","w",stdout);
char ch[105];
chc['U']=0,chc['L']=1,chc['R']=2,chc['D']=3;
while(scanf("%s",ch)){
if(ch[0]=='#')
break;
int n=strlen(ch);
memset(dp,0,sizeof(dp));
for(int i=n-1;i>=0;i--){
for(int a=0;a<4;a++){
for(int b=0;b<4;b++){
if(a!=b){
for(int s=0;s<3;s++){
dp[i][a][b][s]=n*10;
if(ch[i]=='.'){
energy(i,a,b,s,0,0);
for(int k=0;k<4;k++){
energy(i,a,b,s,k,LEFT);
energy(i,a,b,s,k,RIGHT);
}
}else{
energy(i,a,b,s,chc[ch[i]],LEFT);
energy(i,a,b,s,chc[ch[i]],RIGHT);
}
}
}
}
}
}
int a=LEFT,b=RIGHT,s=0;
for(int i=0;i<n;i++){
int f=action[i][a][b][s].f;
printf("%c",foot[f]);
int t=action[i][a][b][s].t;
s=f;
if(f==LEFT){
a=t;
}else if(f==RIGHT){
b=t;
}
}
printf("\n");
}
return 0;
}