51nod 1572 宝岛地图(思维)

本文介绍了一种寻宝游戏中的算法实现,通过预处理地图数据并优化路径搜索过程,有效地解决了从已知地点出发寻找宝藏的问题。文章详细阐述了如何避免重复计算,利用数据结构快速判断障碍物位置,从而极大提升了算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

藏宝图可以用一个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”是一个整数,范围在110001,1000
Output
共一行,按字典序升序打印出所有可以完整执行地图中指令的已知区域的字母,如果没有满足要求的已知区域,则打印“no solution”(没有引号)。
Sample Input
输入样例1
6 10
##########
#K#..#####
#.#..##.##
#..L.#...#
###D###A.#
##########
4
N 2
S 1
E 1
W 2
Sample Output
输出样例1
AD

————————————————————————————————————————————

本题先是用暴力把每个指令都模拟一遍,有几个测试点超时,然后发现没必要一步一步的走,如果能判断直接行走len步的过程中是否遇见#就方便多了,所以先输入地图的时候预处理出每一行中有#的是哪几列,每一列中有#的是哪几行,然后按照每一步的指令方向走,如果#在行走的区间内就标记终止循环。

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int M = 1005;
vector<int>column[M];
vector<int>row[M];
char map[M][M];
struct Node
{
    int x;
    int y;
    bool exist=false;
}ch[26];
struct Operate
{
    int len;
    char dir;
}op[100005];
bool ans[26];
int main()
{
    int n,m;
    memset(ans, false, sizeof(ans));
    char c;
    bool flag;
    scanf("%d%d", &n, &m);
    getchar();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            map[i][j] = getchar();
            c=map[i][j];
            if(c>='A'&&c<='Z')
            {
                ch[c-'A'].exist = true;
                ch[c-'A'].x = i;
                ch[c-'A'].y = j;
            }
            else if(c=='#')
            {
                column[j].push_back(i);
                row[i].push_back(j);
            }
        }
        getchar();
    }
    int k;
    scanf("%d", &k);
    getchar();
    for(int i=1;i<=k;i++)
    {
        scanf("%c %d", &op[i].dir, &op[i].len);
        getchar();
    }
    int xt,yt,xtt,ytt;
    for(int i=0;i<26;i++)
    {
        if(ch[i].exist)
        {
      //      printf("-----------%c\n", 'A' +i);
            flag = true;
            xt = ch[i].x;
            yt = ch[i].y;
            for(int j=1;j<=k;j++)
            {
                if(op[j].dir=='N')
                {
                    xtt = xt - op[j].len;
                    if(xtt<=1)
                    {
                        flag = false;
                        break;
                    }
                    vector<int>::iterator it=column[yt].begin();//vector迭代器,it相当于指针
                    for(;it!=column[yt].end();it++)
                    {
                        if(xt-*it>0&&xt-xtt>=xt-*it)
                        {
                            flag = false;
                            break;
                        }
                    }
                    if(flag)
                        xt = xtt;
                }
                else if(op[j].dir=='S')
                {
                    xtt = xt + op[j].len;
                    if(xtt>=n)
                    {
                        flag = false;
                        break;
                    }
                    vector<int>::iterator it=column[yt].begin();
                    for(;it!=column[yt].end();it++)
                    {
                        if(*it-xt>0&&*it-xt<=xtt-xt)
                        {
                            flag = false;
                            break;
                        }
                    }
                    if(flag)
                        xt = xtt;
                }
                else if(op[j].dir=='W')
                {
                    ytt = yt - op[j].len;
                    if(ytt<=1)
                    {
                        flag = false;
                        break;
                    }
                    vector<int>::iterator it=row[xt].begin();
                    for(;it!=row[xt].end();it++)
                    {
                      //  printf("W=%d\n", *it);
                        if(yt-*it>0&&yt-ytt>=yt-*it)
                        {
                            flag = false;
                            break;
                        }
                    }
                    if(flag)
                        yt = ytt;
                }
                else if(op[j].dir=='E')
                {
                    ytt = yt + op[j].len;
                    if(ytt>=m)
                    {
                        flag = false;
                        break;
                    }
                    vector<int>::iterator it=row[xt].begin();
                    for(;it!=row[xt].end();it++)
                    {
                        if(*it-yt>0&&ytt-yt>=*it-yt)
                        {
                            flag = false;
                            break;
                        }
                    }
                    if(flag)
                        yt = ytt;
                }
                if(!flag)
                    break;
            //    printf("xt=%d yt=%d\n", xt, yt);
            }
            if(flag)
                ans[i] = true;
            else
                continue;
        }
    }
    int cnt=0;
    for(int i=0;i<26;i++)
    {
        if(ans[i])
            printf("%c", 'A'+i);
        else
            cnt++;
    }
    if(cnt==26)
        printf("no solution");
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值