【启发式搜索】2018年东北农业大学春季校赛-H wyh的吃鸡

wyh的吃鸡

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

最近吃鸡游戏非常火,你们wyh学长也在玩这款游戏,这款游戏有一个非常重要的过程,就是要跑到安全区内,否则就会中毒持续消耗血量,我们这个问题简化如下

假设地图为n*n的一个图,图中有且仅有一块X的联通快代表安全区域,有一个起点S代表缩圈的时候的起点,图中C代表的是车(保证车的数量小于等于100),标记为.的代表空地,可以任意通过,O代表障碍物不能通过。每次没有车的时候2s可以走一个格(只能走自己的上下左右4个方向),有车的话时间为1s走一个格

现在告诉你最多能坚持的时间为t秒,问你在t秒内(含t秒)能否从s点到达安全区域,能的话输出YES,并且输出最短时间,不能的话输出NO

输入描述:

输入第一行一个整数T(1<=T<=10)
接下来有T组测试数据,每组测试数据输入2个数n和k(1<=n<=100,1<=k<=10^9)
接下来n行,每行n个字符,代表对应的n*n的地图,每个字符都是上面的一种,并且保证只有一个起点,只有一块安全区域。

输出描述:

对于每组测试数据,先输出能否到达,能的话输出YES,然后换行输出最短时间,如果不能的话直接输出NO

示例1

输入

3
2 3
.X
S.
2 3
.X
SC
2 4
.X
S.

输出

NO
YES
3
YES
4

思路

方法1

今天看到题解了,发现其实两边bfs就可以过。
来源:官方题解
这里写图片描述

方法2

启发式搜索,建立一个优先队列。
估值函数为从起点到这一点的花费。
优先队列的规则为始终优先拓展估值函数值小的点。
然后vis标记数组注意并没有说不能重复走,因为存在可能到毒里面拿车之后再回来的情况。开一个三位数组来当标记数组。简单来说,走路不能重复走走路走过的地方,坐车不能重复走过坐车的地方,但是坐车可以重复走走路走过的地方,很奇怪的规则吧233.
不过这样子就是最优解。

坑点

我也是第一次遇到启发式搜索啊
其实这道题有最优搜索模式,就是官方题解的那两种,不是直接到,就是找到车之后再到,别的走法绝对会比这两种方法花费的多。
说白了还是自己太菜。

AC代码

#include<bits/stdc++.h>
using namespace std;
char Map[106][106];
int vis[106][106][2];
int n,m;
int f[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
typedef struct{
    int x;int y;
    int mod;
    int ans;//估值函数
}poi;

struct cmp//比较规则,在队列里面由小到大排列。
{
    bool operator()(poi a,poi b)
    {
        return a.ans > b.ans;
    }
};

bool judge(int x,int y,int mode)
{
    if(x>=0&&x<n&&y>=0&&y<n&&vis[x][y][mode]==-1&&Map[x][y] != 'O')
        return true;
    else return false;
}

int head(int x,int y)
{
    memset(vis,-1,sizeof(vis));
    poi start;
    vis[x][y][0] = 1;

    start.x = x;
    start.y = y;
    start.mod = 0;
    start.ans = 0;
    priority_queue<poi,vector<poi>,cmp > q;
    q.push(start);
    while(!q.empty())
    {
        poi then;
        then = q.top();
        q.pop();
        if(then.ans > m) return 0x3f3f3f3f;
        if(Map[then.x][then.y]=='X'){
            return then.ans;
        }
        for(int i = 0 ; i < 4; i++)
        {

            poi next;
            next.x = then.x+f[i][0];
            next.y = then.y+f[i][1];
            int tempmod;
            if(then.mod){
                tempmod = 1;
            }
            else tempmod = 0;
            if(judge(next.x,next.y,tempmod)){
                /*换车操作*/
                if(Map[next.x][next.y]=='C'){

                    next.mod = 1;
                }
                else next.mod = then.mod;

                if(then.mod){
                    next.ans = then.ans+1;
                }
                else next.ans = then.ans+2;

                /*标记换车操作*/
                if(next.mod){
                    vis[next.x][next.y][1] = 1;
                }
                else vis[next.x][next.y][0] = 1;
                if(next.ans <= m) //这一个if可以不要。
                    q.push(next);
            }
        }
    }
    return 0x3f3f3f3f;
}

void solve(void)
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i = 0 ; i < n ; i++){
            cin>>Map[i];
        }
        int startx,starty;
        for(int i = 0 ; i < n ; i++){
            for(int j = 0 ; j < n ; j++){
                if(Map[i][j]=='S'){
                    startx = i;
                    starty = j;
                    goto mark;
                }
            }
        }
        mark:;
        int anst = head(startx,starty);
        if(anst<=m){
            cout<<"YES"<<endl;
            cout<<anst<<endl;
        }
        else cout<<"NO"<<endl;
    }
}

int main(void)
{
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/peng0614/article/details/79850973
今日推荐