UVA 10618 跳舞机 (多阶段决策问题)

本文深入解析了一种复杂的路径规划算法,旨在寻找在给定路径上,从初始位置出发,左右脚交替行走,到达每个箭头位置时的最小能量消耗。通过动态规划方法,详细阐述了状态转移方程及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:有点复杂,据说紫书P291描述的题意有误,可以参考https://www.cnblogs.com/sahdsg/p/10596948.html

分析:d[i][a][b][s]表示分析到第i个箭头时,此时左脚处于a,右脚处于b,上次移动的脚为s时的最小能量消耗。细节很多。

参考:https://www.cnblogs.com/SilverNebula/p/5849425.htmlhttps://www.cnblogs.com/zyb993963526/p/6494210.html

LRJ代码:

#include<bits/stdc++.h>
using namespace std;
const int UP = 0;
const int LEFT = 1;
const int RIGHT = 2;
const int DOWN = 3;
const int maxn = 70 + 5;
// d[i][a][b][s] means the minimal future energy when you already tapped i notes
// your left foot at a, right foot at b, last foot is s
int d[maxn][4][4][3];

// if the optimal strategy is to move foot f(0~2) to position t, action=f*4+t
int action[maxn][4][4][3];
char seq[maxn], pos[256], footch[] = ".LR";
// energy needed to move a foot FOR THE SECOND TIME, from a to ta
int energy(int a, int ta) {
  if(a == ta) return 3;
  if(a + ta == 3) return 7; // across
  return 5; // adjacent
}

int energy(int i, int a, int b, int s, int f, int t, int& ta, int& tb) {
  ta = a; tb = b;
  if(f == 1) ta = t;
  else if(f == 2) tb = t;
  // check target arrows
  if(ta == tb) return -1;
  if(ta == RIGHT && tb == LEFT) return -1;
  if(a == RIGHT && tb != b) return -1; // you can't move you right foot before your left foot comes back
  if(b == LEFT  && ta != a) return -1;
  // compute energy
  int e;
  if(f == 0) e = 0; // no move
  else if(f != s) e = 1; // alternative foot, low energy
  else {
    if(f == 1) e = energy(a, ta);
    else e = energy(b, tb);
  }
  return e;
}

// update state (i,a,b,s). foot f is moved to t
void update(int i, int a, int b, int s, int f, int t) {
  int ta, tb;
  int e = energy(i, a, b, s, f, t, ta, tb);
  if(e < 0) return; // invalid
  int cost = d[i+1][ta][tb][f] + e;
  int& ans = d[i][a][b][s];
  if(cost < ans) {
    ans = cost;
    action[i][a][b][s] = f * 4 + t;
  }
}

int main() {
  pos['U'] = 0; pos['L'] = 1; pos['R'] = 2; pos['D'] = 3;
  while(scanf("%s", seq) == 1) {
    if(seq[0] == '#') break;
    int n = strlen(seq);
    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)
          for(int s = 0; s < 3; s++) {
            d[i][a][b][s] = 10*n;
            if(seq[i] == '.') {
              update(i, a, b, s, 0, 0); // no move
              for(int t = 0; t < 4; t++) {
                update(i, a, b, s, 1, t); // move left foot
                update(i, a, b, s, 2, t); // move right foot
              }
            } else {
              update(i, a, b, s, 1, pos[seq[i]]); // move left foot
              update(i, a, b, s, 2, pos[seq[i]]); // move right foot
            }
          }

    // print solution
    int a = LEFT, b = RIGHT, s = 0; // d[0][1][2][0] is out answer
    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", footch[f]);
      s = f;
      if(f == 1) a = t;
      else if(f == 2) b = t;
    }
    printf("\n");
  }
  return 0;
}

 

{************************************************************** 跳舞机 ver 1.0 作者:萧寒 (chinasf) !QQ:410000 e-Mail:chinasf@hotmail.com 开发环境:Delphi 7.0 , DirectX 9.0 SDK 资源内容:源码+执行文件+资源文件 1.wav 背景声音,也是游戏的核心 L1.Lvl 文本文件,可编辑,是舞步脚本 (由于WAV文件格式太大,所以音乐文件只一个,并且很短,舞步脚本节拍 是随手输入的,调整 metronome 常量可以修改节拍器,我对音乐不了解, 所以我做不了这些事情,sorry.) 一个跳舞机游戏框架,类的独立性不强,因为程序不大;所以很多地方 是简化了与类的交互,但还是具有很强的扩展性。 已公布的源码有:欢乐五子棋(GDI 版和 C#-GDI+ 版本) 该源码的算法简单,只针对游戏编程爱好者和初学者,仅供参考,不得 用于商业用途,另外,图形资源原稿修改于vb所编写的跳舞机,作者是 s5851217@cc.hwh.edu.tw ,该作者vb的代码是GDI写的,用了内存绘图 机制,是个学习的好题材,本程序的舞步脚本格式就是参照他的,只做了 小小改动,thank! 跳舞机的舞步脚本格式如下: 标准 Windows 文本文件格式 行1,保存声音文件的路径和文件名,如: c:1.WAV 从行2开始的格式是 int,int,int,int NextTime(DWORD) 比如: 1001 100 前四位表示四个方向的按键图象,为0 则不现,为1 则显示,1001 表示显示Left 和 Right 100 这个值表示 秒/1000 ,一个时间值,可以用小写 x 表示,默认为2700 ,既 2.7 秒 到行尾则该关结束; 评判是否到下关,可以检查 MainForm 类的 DeadCount 整形 如:失误小于 10 个 ( if MainForm.DeadCount<10 then ContinueNextLevelGame; ) 程序花了两个下班的休息时间,最后祝大家学习愉快!望与爱好者交流探讨与研究。 2003.9.26 00:50 **************************************************************} 下载地址: http://www.bssoft.com.cn/DDR.rar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值