UVa10618跳舞机

题意长且烦:
https://vjudge.net/problem/UVA-1252
思路:信息量太杂,理不过来…
看了LRJ大佬的代码,nb。
定义状态:d[i][a][b][s]:已经踩了 i 个箭头,左右脚在a,b上,上一时刻移动的脚是s。
当字母是’.'时,有3种决策:不动,左脚移动,右脚移动。
当字母是箭头时:有2种决策,左脚移动到目标,右脚移动到目标。
能量的计算: t 时刻的能量需要参看 t-1 时刻的状态。比如,如果t-1时刻动的是左脚,那么如果t时刻还动左脚的话,有3种情况:移动到自身(3);移动到相邻(5);移动到对面(7)。如果t时刻动的是右脚,能量为1。
从后往前递推,并记录下每一步移动的脚。结果是d[0][1][2][0]。

#include <cstdio>
#include <cstring>
#include <algorithm>
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]: 已经踩了 i 个箭头,左右脚在a,b上,上一时刻移动的脚是s
//s: 0-没移动;1-左脚移动;2-右脚移动 
int d[maxn][4][4][3], n;

// 如果动作是把f脚移动到t,action = f * 4 + t; 
int action[maxn][4][4][3];

char seq[maxn], pos[256], footch[] = ".LR";

// 某只脚的连续第二次移动 
int energy(int a, int ta){
	if(a == ta) return 3;
	if(a + ta == 3) return 7;
	return 5;
}

// 状态(i,a,b,s)下,把 f脚 移动到t所花费的最少能量。ta,tb是这次移动之后的左右脚位置。 
int energy(int i, int a, int b, int s, int f, int t, int& ta, int& tb){
	ta = a; tb = b;
	if(f == LEFT) ta = t;  // 如果移动的是左脚,更新左脚位置 
	else if(f == RIGHT) tb = t; 
	
	// 判断移动是否合理
	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 ;
	if(f == 0) e = 0; // 不移动
	else if(f != s) e = 1; // 这只脚上次没移动
	else {
		if(f == LEFT) e = energy(a, ta);
    	else e = energy(b, tb);
	} 
	return e;
}

// 状态(i,a,b,s)下,把f移动到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;
	
	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;
	}
}

void solve(){
	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); // 不动
			for(int t = 0; t < 4; ++t){
				update(i,a,b,s, LEFT, t); // 动左脚 
				update(i,a,b,s, RIGHT, t); // 动右脚 
			} 
		}
		else{
			update(i,a,b,s,LEFT,pos[seq[i]]); // 动左脚 
			update(i, a, b, s, RIGHT, pos[seq[i]]); // 动右脚
		}
	}
	
}

void print_solution(){
	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",footch[f]);
		s = f;
		if(f == LEFT) a = t;
		else if(f == RIGHT) b = t;
	}
	printf("\n");
} 

int main()
{
	freopen("in.txt","r",stdin);
	pos['U'] = 0; pos['L'] = 1; pos['R'] = 2; pos['D'] = 3;
	
	while(scanf("%s",seq) == 1){
		if(seq[0] == '#') break;
    	n = strlen(seq);
    	memset(d, 0, sizeof(d));
    	
    	solve();
    	print_solution();
	}

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值