第九章-竞赛题目选讲-跳舞机

UVA10618 跳舞机 Tango Tango Insurrection

题目

题解

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
/*
    Up-上- 0  Left-左- 1  Down-下- 2  Right-右- 3
    根据能量消耗, 逆向dp 计算最优选择:目标dp[0][1][3][0]
dp(i,a,b,s)表示踩第i个箭头,左脚在a上,右脚在b上,上一个移动的脚为s
        (s: 0-没有脚移动;1-左脚移动;2-右脚移动)
    
*/
const int UP = 0, LEFT = 1, RIGHT = 2, DOWN = 3;
const int MAXN = 105;
const int INF = 0x3f3f3f3f;//无穷大
int n;
char in[MAXN];//存储输入
int dp[MAXN][4][4][3];
int action[MAXN][4][4][3];//记录决策(压缩存储)
int pos[MAXN];//字符转编号
char foot[] = ".LR";

int move_energy(int from, int to) {// 单脚连续两次移动的能量
    if (from == to) return 3;
    if (from + to == 3) return 7;
    return 5;
} 

int energy(int a, int b, int s, int f, int t, int ta, int tb) {
    // 非法状态判断
    if (ta == tb) return -1;
    if (ta == RIGHT && tb == LEFT) return -1;
    if (a == RIGHT && tb != b) return -1; // 左脚在右箭头上时,右脚不能动
    if (b == LEFT && ta != a) return -1;  // 右脚在左箭头上时,左脚不能动

    // 能量计算
    int e = 0;
    if(f == 0) e = 0;          // 不动
    else if (f != s) e = 1;     // 换脚
    else {                      // 同脚连踩
        if (f == 1) e = move_energy(a, ta);
        else e = move_energy(b, tb);
    }
    return e;
}

void update(int i, int a, int b, int s, int f, int t) {
    int ta = a,tb = b;//ta-左脚新位置 与tb-右脚新位置
    if(f == 1) ta = t;//左脚移动到t
    else if(f == 2) tb = t;//右脚移动到t
    
    int e = energy(a, b, s, f, t, ta, tb);//计算能量消耗
    if (e < 0) return;
    
    //计算能量花费并更新当前dp为最小值
    int cost = dp[i+1][ta][tb][f] + e;
    if (cost < dp[i][a][b][s]){
        dp[i][a][b][s] = cost;
        action[i][a][b][s] = f * 4 + t; // 压缩存储
    }
}

void solve(){
    n = strlen(in);
    memset(dp,0,sizeof(dp));//dp初始化
    memset(action, 0, sizeof(action));//action初始化
    //逆推
    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++){ //上一次移动的是哪只脚(都没动 or 左脚动 or 右脚动)
                    dp[i][a][b][s] = INF;//初始化为无穷大,方便记录最小能量消耗时的状态
                    if(in[i] == '.'){//当前是空拍 '.'
                        update(i,a,b,s,0,0);//不动
                        for (int t = 0;t < 4;t++){//动(左 or 右)脚到t ,为下一步做准备
                            update(i, a, b, s, 1, t);//左脚动
                            update(i, a, b, s, 2, t);//右脚动
                        }
                    }else{
                        int t = pos[in[i]];//当前目标方向
                        update(i, a, b, s, 1, t);//左脚动
                        update(i, a, b, s, 2, t);//右脚动
                    }
                }
            }
        }
    }

    // 输出方案
    int a = LEFT, b = RIGHT, 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", foot[f]);
        s = f;
        if (f == 1) a = t;
        else if (f == 2) b = t;
    }
    printf("\n");
}
int main(){
    pos['U'] = UP; pos['L'] = LEFT; pos['R'] = RIGHT; pos['D'] = DOWN;
    while(scanf("%s",in) == 1){
        if (in[0] == '#') break;
        solve();
    }
}
相关推荐
近津薪荼3 小时前
优选算法——前缀和(5):和为 K 的子数组
算法
鲨鱼吃橘子4 小时前
C++刷题--递归回溯剪枝(二)
开发语言·数据结构·c++·算法·leetcode·深度优先·剪枝
plus4s11 小时前
2月12日(70-72题)
算法
m0_6727033111 小时前
上机练习第24天
算法
edisao12 小时前
序幕-内部审计备忘录
java·jvm·算法
shehuiyuelaiyuehao12 小时前
22Java对象的比较
java·python·算法
Dev7z13 小时前
滚压表面强化过程中变形诱导位错演化与梯度晶粒细化机理的数值模拟研究
人工智能·python·算法
吴秋霖13 小时前
apple游客下单逆向分析
python·算法·逆向分析
YunchengLi15 小时前
【计算机图形学中的四元数】2/2 Quaternions for Computer Graphics
人工智能·算法·机器学习