51nod 1572 宝岛地图(预处理+模拟)

32 篇文章 0 订阅
8 篇文章 0 订阅

Description

勇敢的水手们到达了一个小岛,在这个小岛上,曾经有海盗在这里埋下了一些宝藏。然而,我们的船快抛锚了,与此同时,船长发现藏宝图的一角被老鼠咬掉了一块。

藏宝图可以用一个n×m大小的矩形表示。矩形中的每一小块表示小岛中的一小块陆地(方块的边长为1米)。有一些方块表示的是海,这些块人是不能通过的。除了海不能走,其它的小方块都是可以行走的。在可行走区域里有一些小方块表示一些已知的地点。

另外,在地图上有k条指令。每条指令的格式表示如下:
“向y方向走n米”。

这里的方向有四种:“北”,“南”,“东”,“西”。如果你正确的跟着这些指令行走,并且完整的执行完所有指令,你就可以找到宝藏所在的地点。

但是,很不幸,由于地图中好多地方都缺失了,船长也不知道从哪些地方开始走。但是船长依然清楚地记得一些已知的地点。另外,船长也知道所有可行走区域。

现在船长想知道从哪些已知地点出发,按照指令,可能找到宝藏所在地。

Input

单组测试数据
第一行包含两整数n和m(3≤n,m≤1000)。
接下来的n行每行有m个字符,表示整个地图。
“#”代表海。在地图矩形中,矩形的四周一圈一定是海。
“.”代表可行走区域,未知地点。大写字母“A”到“Z”表示可行走区域,已知地点。
所有大写字母不一定都被用到。每个字母在地图中最多出现一次。所有已知地点用不同的大写字母表示。

接下来一行有一个整数k(1≤k≤10^5),接下来有k行。
每行表示一条指令。
指令格式为“dir len”,“dir”表示朝哪个方向走,“len”表示走几步。
“dir”有四种取值“N”,“S”,“E”,“W”,对应题目中的“北”,“南”,“东”,“西”
在地图中,北是在顶部,南是在底部,西是在左边,东是在右边。“len”是一个整数,范围在[1,1000]。

Output

共一行,按字典序升序打印出所有可以完整执行地图中指令的已知区域的字母,如果没有满足要求的已知区域,则打印“no solution”(没有引号)。

Input示例

6 10
##########
#K#..#####
#.#..##.##
#..L.#...#
###D###A.#
##########
4
N 2
S 1
E 1
W 2

Output示例

AD

解题思路

dp[i][j][k]代表在(i,j) 的位置可以向k 方向走多少步,
预处理好了之后直接模拟每一个可知区域.

代码实现

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);
typedef long long ll;
const int maxn=1007;
const int maxm=1e5+7;
char maps[maxn][maxn];
int dp[maxn][maxn][4]; //0N 1S 2E 3W
int op[maxm],step[maxm];
int m,n;
struct node
{
    int x;
    int y;
} point[30];
void init()
{
    for(int i=0; i<m-1; i++)
        for(int j=0; j<n-1; j++)
        {
            if(maps[i][j]=='#')
            {
                dp[i][j][0]=-1;
                dp[i][j][3]=-1;
            }
            else
            {
                dp[i][j][0]=dp[i-1][j][0]+1;
                dp[i][j][3]=dp[i][j-1][3]+1;
            }
        }
    for(int i=m-1; i>=0; i--)
        for(int j=n-1; j>=0; j--)
        {
            if(maps[i][j]=='#')
            {
                dp[i][j][2]=-1;
                dp[i][j][1]=-1;
            }
            else
            {
                dp[i][j][2]=dp[i][j+1][2]+1;
                dp[i][j][1]=dp[i+1][j][1]+1;
            }
        }
}
int main()
{
    IO;
    int k;
    cin>>m>>n;
    memset(point,-1,sizeof(point));
    for(int i=0; i<m; i++)
    {
        cin>>maps[i];
        for(int j=0; j<n; j++)
            if(maps[i][j]>='A'&&maps[i][j]<='Z')
            {
                point[maps[i][j]-'A'].x=i;
                point[maps[i][j]-'A'].y=j;
            }
    }
    init();
    cin>>k;
    char ch;
    for(int i=0; i<k; i++)
    {
        cin>>ch>>step[i];
        if(ch=='N') op[i]=0;
        else if(ch=='W') op[i]=3;
        else if(ch=='E') op[i]=2;
        else op[i]=1;
    }
    bool flag=false;
    for(int i=0; i<26; i++)
    {
        if(point[i].x!=-1&&point[i].y!=-1)
        {
            bool mark=true;
            int tx=point[i].x,ty=point[i].y;
            for(int j=0; j<k; j++)
            {
                if(step[j]>dp[tx][ty][op[j]])
                {
                    mark=false;
                    break;
                }
                else
                {
                    if(op[j]==0) tx-=step[j];
                    else if(op[j]==1) tx+=step[j];
                    else if(op[j]==2) ty+=step[j];
                    else ty-=step[j];
                }
            }
            if(mark)
            {
                flag=true;
                cout<<char(i+'A');
            }
        }
    }
    if(!flag)
        cout<<"no solution";
    cout<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值