简介:
跳舞机
分析:
限制条件较多的一个动态规划
状态很好理解,但是限制特别多
d[i][a][b][s]表示到达第i个指示灯的时候,左脚在a,右脚在b,上一次移动的脚为s(没有移动0,左脚1,右脚2)所需的最小花费
将四个方向分别编号为上0,下3,左1,右2.
这样编码的方式有一个方便之处:求相对的方向只要和为3即可
状态转移如下:
- 如果当前是 ’ . ‘,有三种决策
- 选择不动
- 左脚移到其他方向
- 右脚移动到其他方向.
- 如果当前是某一个方向,有两种决策
- 左脚移动到该位置上
- 右脚移动到该位置上.
注意不要枚举不合法的移动:
不合法的移动:
- 左脚在右箭头上,右脚在左箭头上
- 两脚在同一箭头上
- 左脚在右箭头上,但是右脚要移动
- 右脚在左箭头上,但是左脚要移动
代码中,我们采用逆推的方式
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int INF=0x33333333;
const int L=1;
const int R=2;
char ss[100];
int d[100][4][4][3],action[100][4][4][3];
int pos[256],n;
char place[]=".LR";
int get(int a,int ta)
{
if (a==ta) return 3; //相同的位置
else if (a+ta==3) return 7; //相对的位置
else return 5; //相邻的位置
}
int energy(int a,int b,int s,int f,int t,int &ta,int &tb)
//a这次的左脚位置 b这次的右脚位置 s上次的动作 f下一次要动的脚 t下一次的动作 ta左脚下次的位置 tb右脚下次的位置
{
ta=a; tb=b;
if (f==1) ta=t; //下次动作由左脚完成
else if (f==2) tb=t;
if (ta==tb) return -1; //踩到同一个位置
if (ta==R&&tb==L) return -1; //背向跳舞机
if (ta==R&&tb!=b) return -1; //a左脚在右脚的位置,但是移动了右脚,无论移动到哪儿,都是不合法的
if (tb==L&&ta!=a) return -1; //b右脚在左脚的位置,但是移动了右脚,无论一定到哪儿,都是不合法的
int e=0;
if (f==0) e=0; //没有脚移动
else if (f!=s) e=1; //上一次移动的脚不是现在移动的脚
else
{
if (f==1)
e=get(a,ta); //移动的是左脚
else
e=get(b,tb); //移动的是右脚
}
return e;
}
void update(int i,int a,int b,int s,int f,int t)
//i踩了几个箭头 a左脚位置 b右脚位置 s上次的动作 f这次要移动的脚 t移动方向
{
int ta,tb;
int e=energy(a,b,s,f,t,ta,tb);
if (e<0) return;
int cost=d[i+1][ta][tb][f]+e; //下次移动情况:ta tb
int &ans=d[i][a][b][s];
if (ans>cost)
{
ans=cost;
action[i][a][b][s]=f*4+t; //
}
}
void doit()
{
n=strlen(ss);
memset(d,0,sizeof(d));
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) continue;
for (int s=0;s<3;s++){ //上一次的动作,1左脚,2右脚
d[i][a][b][s]=INF;
if (ss[i]=='.')
{
update(i,a,b,s,0,0); //两脚都不动
for (int t=0;t<4;t++)
{
update(i,a,b,s,1,t);
update(i,a,b,s,2,t);
}
}
else
{
update(i,a,b,s,1,pos[ss[i]]);
update(i,a,b,s,2,pos[ss[i]]);
}
}
}
}
}
}
void print()
{
int a=1;
int b=2;
int s=0;
for (int i=0;i<n;i++)
{
int f=action[i][a][b][s]/4;
int t=action[i][a][b][s]%4;
printf("%c",place[f]);
s=f;
if (f==1) a=t;
else if (f==2) b=t;
}
printf("\n");
}
int main()
{
pos['U']=0;
pos['D']=3;
pos['L']=1;
pos['R']=2;
while (scanf("%s",&ss)!=EOF&&ss[0]!='#')
{
doit();
print();
}
return 0;
}