本质上就是个简单的动规,但是各种条件限制太鬼畜了……
强行肝了大概四个多小时总算肝过去了,其中有三个小时是没发现输出代码有bug,一直在调已经对了的其他部分……
开四维数组f[决策步数][左脚位置][右脚位置][移动情况(不动|动左脚|动右脚)]=最小能量消耗,再开一个四维数组存储路径。
如果是‘.’那么枚举各种走法取最优方案,如果是按键,枚举左脚或者右脚去踩,取最优方案。
由于前一步的动作会影响到下一步的能量消耗,所以需要倒着动规。原本写了倒序循环的动规,在↑那心力交瘁的三个小时里改成了类DFS的形式……
代码写得很详细了:
1 //紫书P290 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int mxn=90; 9 struct node{ 10 int l,r,last; 11 }ap[mxn][6][6][6]; 12 int f[mxn][6][6][6]; 13 //[已决策步数][左脚(上,下,左,右)][右脚(上,下,左,右)][上次移动脚(无,左,右)] 14 // 0 1 2 3 0 1 2 15 char s[mxn]; 16 int n; 17 bool pd(int l,int r,int nl,int nr){//移动合法性判断 18 if(nl==l && nr==r)return 1; 19 if(nl==l)//左脚不动 20 if(nr!=l && l!=3)return 1; 21 if(nr==r)//右脚不动 22 if(nl!=r && r!=2)return 1; 23 return 0; 24 } 25 int cost(int f,int t,int last,int now){//起点,终点,上次移动脚,本次移动脚 26 if(last!=now)return 1;//无动作 27 if(f==t)return 3;//只踩不移动 28 if(f!=(t^1))return 5;//移动到相邻位置 29 return 7;//移动到相对位置 30 } 31 int dp(int i,int l,int r,int last){ 32 int& ans=f[i][l][r][last];//动规答案 33 node& a=ap[i][l][r][last];//路径 34 if(ans!=0x3f3f3f3f)return ans; 35 if(i==n)return ans=0;//到达起始状态,递归返回 36 if(s[i]=='.'){ 37 //不移动 38 ans=min(ans,dp(i+1,l,r,0)); 39 a.l=l;a.r=r;a.last=0; 40 //四方向移动 41 for(int j=0;j<4;j++){ 42 //动左脚 43 if(pd(l,r,j,r)){ 44 int tmp=dp(i+1,j,r,1)+cost(l,j,last,1); 45 if(ans>tmp){ 46 ans=tmp; 47 a.l=j;a.r=r;a.last=1; 48 } 49 } 50 //动右脚 51 if(pd(l,r,l,j)){ 52 int tmp=dp(i+1,l,j,2)+cost(r,j,last,2); 53 if(ans>tmp){ 54 ans=tmp; 55 a.l=l;a.r=j;a.last=2; 56 } 57 } 58 } 59 return ans; 60 } 61 // else{ 62 int dir=0;//目标移动方向 63 switch(s[i]){ 64 case 'L':{dir=2;break;} 65 case 'R':{dir=3;break;} 66 case 'U':{dir=0;break;} 67 case 'D':{dir=1;break;} 68 } 69 70 //动右脚 71 if(pd(l,r,l,dir)){ 72 int tmp=dp(i+1,l,dir,2)+cost(r,dir,last,2); 73 if(tmp<ans){ 74 ans=tmp; 75 a.l=l;a.r=dir;a.last=2; 76 } 77 } 78 //动左脚 79 if(pd(l,r,dir,r)){ 80 int tmp=dp(i+1,dir,r,1)+cost(l,dir,last,1); 81 if(tmp<ans){ 82 ans=tmp; 83 a.l=dir;a.r=r;a.last=1; 84 } 85 } 86 return ans; 87 // } 88 } 89 void Print(){//输出方案 90 int nl=2,nr=3,last=0;//初始状态 91 for(int i=0;i<=n;i++){ 92 int tpl=nl,tpr=nr,tplast=last; 93 if(i>0){ 94 if(last==0)printf("."); 95 else if(last==1)printf("L"); 96 else printf("R"); 97 } 98 nl=ap[i][tpl][tpr][last].l; 99 nr=ap[i][tpl][tpr][last].r; 100 last=ap[i][tpl][tpr][last].last; 101 } 102 return; 103 } 104 int main(){ 105 int i,j; 106 while(scanf("%s",s) && s[0]!='#'){ 107 memset(f,0x3f,sizeof f); 108 n=strlen(s); 109 dp(0,2,3,0);//从初始状态开始动规 110 Print(); 111 printf(" "); 112 } 113 return 0; 114 }