紫书的代码 多转移问题 从终点逆推
#include<cstdio>
#include<cstring>
#include<cassert>
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
// 在第i个箭头的左脚在a右脚在b 上一次移动了脚s
// 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
// 从a到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;//左脚到t
else if(f == 2) tb = t;//右脚到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;
// 如果动作可以执行 计算消耗的能量
int e;
if(f == 0) e = 0; // 不动不用踩 不用消耗能量
else if(f != s) e = 1; // 要用的这个脚上次脚没动作 则只要消耗能量1
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;//由i+1转移到i 但是主程序是逆推
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 刚开始左脚在1 右脚在b 上一次没动脚 从第1个箭头开始
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;
}