Codevs 2547 东方辉针城

2547 东方辉针城
时间限制: 1 s
空间限制: 32000 KB
题目等级 : 黄金 Gold
题目描述 Description
将于5月26日发售的东方辉针城在东方吧中引起了很多关注…

这个游戏是这样的,需要你操控一名角色,去和其他的杂鱼和boss决战。而对方和你的攻击的手段都是弹幕。在游戏中,你需要躲避他人的弹幕,并发射出自己的弹幕来攻击对方。本题中,为简单起见,只考虑对方发射的弹幕。

假设主角始终处于画面低端,将每秒与主角出现在一排的弹幕进行叠加,总共游戏进行了T秒,可以形成一个(T+1)×WIDTH大小的字符矩阵,“.”表示该点为空,“*”表示该点有至少一颗子弹。

现在告诉你主角的初始位置,求能否不中弹经过这T秒的弹幕,和操作的步骤。(主角不会⑨的)

题目认为抵达最后一行即视为通过,如果有多种不同的选择可以抵达最后一行请优先向左,其次不动,最后向右;题目保证数据合法且初始位置无弹幕。

输入描述 Input Description
输入数据包括T+3行。
第1行为两个正整数T和WIDTH,分表表示游戏进行的时间和屏幕的宽度。
第2行为一个正整数S,为初始的位置。
第3~T+3行每行包括WIDTH个字符,表示该点的状态。

输出描述 Output Description
第1行为一个字符串“Yes”或者“No”。表示能否不中弹通过此区域。
第2行为一个字符串,如果出现中弹则不输出。表示通过T秒的操作,“L”表示向左移动一个格子,“R”表示向右移动一个格子,“N”表示不动。

样例输入 Sample Input
8 5
3
…..
…..
..*
..*
..*
..*
*.*
…..
…..

样例输出 Sample Output
Yes
NRNNNNLL

数据范围及提示 Data Size & Hint
1≤T≤1000, 1≤WIDTH≤100


思路

本题经典搜索,可能有一些人一下看不懂题目意思,那我先说一下题目大意。
给你一个字符矩阵,按照题目的优先级选择路径。

题目给的T为8,但矩阵却有九排,那是因为主角移动是从第二排开始,
一共移动了8排,WIDTH代表一排有几个位置,按照优先级,
主角当下一排的左边位置没有子弹(*)时先向左走,左边不能走时走中间,
最后走右边。如果走不出去,就输出”No”。

方法一

其实这个题目可以用回溯,当一条路走不通时,就返回上一级,走下一条路,
知道全走通或走不通。
代码如下:

#include<cstdio>
#include<iostream>
#define M 1010
using namespace std;
int map[M][M],vis[M][M],a[M],T,n,flag;
void dfs(int t,int pos)
{
    if(flag==1)return;
    if(t==T)
    {
        printf("Yes\n");
        for(int i=1;i<=T;i++)
          printf("%c",(char)a[i]);
        flag=1;
        return;
    }
    if(map[t+1][pos-1]=='.'&&!vis[t+1][pos-1])
    {
        a[t+1]='L';
        vis[t+1][pos-1]=1;
        dfs(t+1,pos-1);
        vis[t+1][pos-1]=0;
    }
    if(map[t+1][pos]=='.'&&!vis[t+1][pos])
    {
        a[t+1]='N';
        vis[t+1][pos]=1;
        dfs(t+1,pos);
        vis[t+1][pos]=0;
    }
    if(map[t+1][pos+1]=='.'&&!vis[t+1][pos+1])
    {
        a[t+1]='R';
        vis[t+1][pos+1]=1;
        dfs(t+1,pos+1);
        vis[t+1][pos+1]=0;
    }
}
int main()
{
    freopen("jh.in","r",stdin);
    scanf("%d%d",&T,&n);
    int Qi;
    char s[M];
    scanf("%d",&Qi);
    for(int i=0;i<=T;i++)
    {
        scanf("%s",s);
        for(int j=1;j<=n;j++)
          map[i][j]=(int)s[j-1];
    }
    dfs(0,Qi);
    if(flag==0)printf("No");
    return 0;
}

方法二

如果你感觉搜索加回溯太长或不符合你的代码风格,
那么这里还有一个简单的代码,没有回溯,但是,思路是一样的。

注意:在dfs函数中,判断是否走通和标志位赋值时,一定要让n>t,
代表走出矩阵,也就是能够走到最后一排,没有弹幕阻挡。

#include<cstdio>
#include"iostream"
using namespace std;
bool f[1050][150];
int a[3]={-1,0,1};
int t,w,l,flag;
char ss[1050];
char lu[3]={'L','N','R'};
void dfs(int n,int last)
{
    if(n>t) {flag=1;cout<<"Yes"<<endl;}//如果找到一条路,标志位赋值1
    else
    for(int i=0;i<3;i++)//按照优先级开一个字符数组
      {

        if(f[n+1][last+a[i]])//如果能走就走
          {
            ss[n]=lu[i];
            dfs(n+1,last+a[i]);
          }
        if(flag) return;//走通了就返回
      }
}
int main()
{
    char s;
    cin>>t>>w>>l;
    for(int i=1;i<=t+1;i++)//将字符矩阵转化成bool型(个人习惯)
      for(int j=1;j<=w;j++)
        {
            cin>>s;
            if(s=='.')
              f[i][j]=1;
        }
    dfs(1,l);//从移动的第一排开始找起
    if(flag)
      for(int i=1;i<=t;i++)
        cout<<ss[i];
    else
      cout<<"No"<<endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值