题目
题目大意
没说太清楚,是这样的:
- 时间从0开始,每1秒走一格,例如1秒时人在最下面的第2列
- 人在地板上,不按按钮会一直往右走
- 人到了天花板,一直按住按钮就会在天花板上往右走
- 人走到最后一列的右面那一列的1-10行算赢
分析
直接可行性DP,外层循环枚举列,如果不是墙的话,每次可以从左上或左下飞过来,加一个天花板和地板的特判即可。
难点是输出方案。
在DP的时候记录一下当前格子是向右、向右上还是向右下飞来的,然后从终点递归,递归参数:
- 当前坐标
x
、y
- 当前已向同一方向走了多久
L
- 当前按了多少次按钮
cnt
- 之前那一步的方向
d
然后就凭感觉写吧。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
#define MAXN 100000
bool dp[15][MAXN+5];
char Map[15][MAXN+5];
int dir[15][MAXN+5];
void Print(int x,int y,int L,int cnt,int d){
if(!dir[y][x]){
printf("%d\n",cnt);
return;
}
int flag=0;
if(dir[y][x]>=1){
if(d==1)
Print(x-1,y+(dir[y][x]==1),L+1,cnt,d);
else
Print(x-1,y+(dir[y][x]==1),1,cnt,1);//到Map[y][x]时停止上升
}
else{
if(d==-1)
Print(x-1,y-(dir[y][x]==-1),L+1,cnt,d);
else
flag=1,Print(x-1,y-(dir[y][x]==-1),1,cnt+1,-1);//从Map[y][x]开始上升
}
if(flag)
printf("%d %d\n",x-1,L);
}
int main(){
freopen("jetpack.in" ,"r", stdin);
freopen("jetpack.out","w",stdout);
int N=read();
for(int i=1;i<=10;i++)
scanf("%s",Map[i]+1);
dp[10][1]=1;
dir[10][1]=-1;
for(int j=2;j<=N+1;j++)
for(int i=1;i<=10;i++){
if(Map[i][j]!='X'){
if(i==1){
if(dp[i][j-1]){
dp[i][j]=1;
dir[i][j]=2;
}
}
if(i==10){
if(dp[i][j-1]){
dp[i][j]=1;
dir[i][j]=-2;
}
}
if(dp[i+1][j-1]){
dp[i][j]=1;
dir[i][j]=1;
}
if(dp[i-1][j-1]){
dp[i][j]=1;
dir[i][j]=-1;
}
}
}
for(int i=1;i<=10;i++)
if(dp[i][N+1]){
Print(N+1,i,0,0,0);
return 0;
}
}