UVA 10618 - Tango Tango Insurrection【DP】

题目大意

传送门

描述
跳舞机的踏板上有四个箭头:上下左右。当舞曲开始的时候,你需要在箭头移动到踏板上的时候,你需要在踏板上踩下相同的箭头。
不需要踩箭头的时候,踩箭头不会受到惩罚,当时需要踩箭头的时候,必须踩一下
踩箭头需要消耗能量,写一个程序来帮助选择轻松的踩踏方式,使得消耗的能量最少。

消耗能量:

  • 如果这个脚上个时间没有任何动作,消耗1单位能量
  • 如果这个脚上个时间没有移动,消耗3单位能量
  • 如果这个脚上个时间移动到相邻箭头,消耗5单位能量
  • 如果这个脚上个时间移动到相对箭头,消耗7单位能量

正常情况下,左脚不能放到右箭头上,但是有一种情况例外:当你的左脚在上箭头或者下箭头,你可以临时扭着身子用右脚踩左箭头,但是在右脚移动之前,左脚不能动。

输入
最多100组数据,每组数据包含一个长度不超过70的字符串。LR表示左右箭头,.表示不需要踩箭头,UD表示上下箭头。

输出
和输入一样长度的字符串,表示每个时间执行动作的脚,LR表示左右脚,.表示不踩。

Sample Input

LRLRLLLLRLRLRRRRLLRRLRLDU…D…UUUUDDDD
#

Sample Output

LRLRLLLLRLRLRRRRLLRRLRLRL…R…LLLLRRRR

思路

dp(i,a,b,s)表示已经踩了i个箭头。
左右脚分别在箭头a和箭头b上,
上一个周期移动的脚为s(s=0表示脚没有移动,s=1表示左脚移动,s=2表示右脚移动)

如果下一步是.,有三种决策:

  • 左脚移动到另一个箭头上
  • 右脚移动到另一个箭头上
  • 不动

如果下一步是4个箭头之一,有两种决策:

  • 左脚移动到该箭头
  • 右脚移动到该箭头。

代码

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

#define maxn 100
char S[maxn];


int dp[maxn][4][4][3];
int action[maxn][4][4][3]; //将移动哪只脚以及方向变成一个整数存进数组

const int LEFT = 1;
const int RIGHT = 2;

int pos[256];

int energy(int l,int tl)
{
    if (l == tl)    return 3; // 相同的位置
    if (l + tl == 3)    return 7; // 相对的位置
    return 5;   // 相邻的位置
}

//l左脚的位置
//r右脚的位置
//m决策
//f左脚或者右脚
//t上下左右
int energy(int l,int r,int m,int f,int t,int &tl,int &tr) //
{
    tl = l;
    tr = r;

    if (f == 1)//左脚
        tl = t;
    else if (f == 2)//右脚
        tr = t;

    if (tl == tr)   return -1; // 下一个状态踩到同一个位置
    if (tl == RIGHT && tr == LEFT) return -1; // 背向跳舞机
    if (l == RIGHT && tr != r)  return -1; // l左脚在右脚的位置,但是移动了右脚,无论移动到哪儿,都是不合法的
    if (r == LEFT  && tl != l)  return -1; // r右脚在左脚的位置,但是移动了左脚,无论移动到哪儿,都是不合法的

    int e = 0;

    if (f == 0) // 没有脚移动
        e = 0;
    else if (f != m) //上一次移动的脚不是现在移动的脚
        e = 1;
    else
    {
        if (f == 1) // 移动的是左脚,
            e = energy(l,tl);
        else        // 移动的是右脚
            e = energy(r,tr);
    }
    return e;


}

//第i个位置
//l左脚的位置
//r右脚的位置
//m决策
//f左脚或者右脚
//t上下左右
void update(int i,int l,int r,int m,int f,int t)
{
    int tl,tr;
    int e;
    e = energy(l,r,m,f,t,tl,tr);

    if (e < 0)
        return ;

    int cost = dp[i+1][tl][tr][f] + e;

    int &ans = dp[i][l][r][m];

    if (ans > cost)
    {
        ans = cost;
        action[i][l][r][m] = f * 4 + t;//将左脚或者右脚以及上下左右组合成一个整数
    }

}

int main ()
{

    pos['U'] = 0;
    pos['D'] = 3;
    pos['L'] = 1;
    pos['R'] = 2;
    char place[] = ".LR";

    while(scanf("%s",S))
    {
        if(S[0] == '#') break;
        int len = strlen(S);

        memset(dp,0,sizeof(dp));

        for(int i = len-1; i>=0; i--)
        {
            for(int l = 0; l<4; l++)
            {
                for(int r = 0; r<4; r++)
                {
                    if(l == r ) continue;
                    for(int m = 0; m<3; m++)
                    {
                        dp[i][l][r][m] = 0x1f1f1f1f;
                        if(S[i] == '.')//3种决策
                        {
                            update(i,l,r,m,0,0);//不动

                            for(int t = 0; t < 4; t++)
                            {
                                update(i,l,r,m,1,t);//移动左脚 移动到位置t
                                update(i,l,r,m,2,t);//移动右脚 移动到位置t
                            }
                        }

                        else//2种决策
                        {
                            update(i,l,r,m,1,pos[S[i]]);//左脚移动到位置S[i]
                            update(i,l,r,m,2,pos[S[i]]);//右脚移动到位置S[i]
                        }
                    }
                }
            }
        }

        int l = 1;
        int r = 2;
        int m = 0;
        for (int i = 0 ; i < len ; i++)
        {
            int f = action[i][l][r][m] / 4;
            int t = action[i][l][r][m] % 4;

            printf("%c",place[f]);

            m = f;

            if (f == 1)
                l = t;
            else if (f == 2)
            {
                r = t;
            }
        }
        puts("");
        //printf("%d\n",d[0][1][2][0]);

    }
}

Hit

状态比较复杂

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章