比赛补题:QUT——This is not easy (BFS)

来源:互联网 发布:java词法分析器 编辑:程序博客网 时间:2024/06/05 22:57

总结

感觉这是能A的最后一道题了,当时手速不够,在加上方法不优,最后没敲出来

上一周结束了基础搜索的专题 还没来的及总结 现在这个就当作总结了 其他的内容搜索题解正在路上

上题

题目描述
Royal in Qingdao university of science and technology, there lived a group of happy acmer, one day, OuYang has something to find
PiaoPiao ,but because PiaoPiao was too lazy, so PiaoPiao told OuYang
his position , let OuYang to look for him.

    In order to simplify the problem, we regard it as a n x n (n<=100)rectangular, OuYang can move to four directions, up, down,

left, right, mobile take a minute at a time.

    Inside the university also live not more than eight dogs, each dog take of a grid, OuYang likes them very much,

when he encounters a dog, he will go to touch it, and touch must spend
extra one minute, but he had a habit is that not touching the same dog
twice a day.

    There is no more than four keys, corresponds to the four types of door, the number of each type of door does not exceed 3.

‘O’stand for OuYang,

‘P’stand for PiaoPiao,

‘#’stand for wall,

‘.’stand for road,

‘D’stand for dog,

‘1’~‘4’stand for four keys,

‘a’~‘d’ stand for four doors。

输入
There are several test cases.

  For each case, the first line includes a integers N (1 < N <= 100) meaning that the palace is a N×N matrix.  Then the N × N matrix follows.  The input ends with end of file.

输出
For each test case, print the minimum time (in minutes) OuYang needed to find PiaoPiao. If it’s impossible for OuYang to
complete the mission, print “GgSmd”(no quotes).

样例输入

4

O…

….

b##a

12#P

5

O….

.1…

…..

Da###

….P

样例输出
GgSmd
8

提示

来源
oyy

翻译

P是飘飘的位置O是欧阳学长的位置要求从O点走到P点

其中小写的a, b, c, d是门需要对应的1, 2, 3, 4 这4把钥匙才能打开

D是狗 延时1秒

分析

标准的BFS(广度优先遍历, 据王卓说深搜也行但还没试验过,以后再补)

下面会在复习一下深搜和广搜,现在谈谈这道题的重点之处

  1. 钥匙的处理

因为钥匙的存在导致在纪录路径的时候不能简单的纪录这个点是否走过(下文的vis【】【】数组)

可以这么想,在路径中存在重复的点,但是第一次走过那个点是为了取钥匙

所以我们要在开标记数组的时候加2维 分别表示手中的钥匙 和打开的门

也就是vis[地图x坐标][地图y坐标][已经拿到的钥匙][已经打开的门]
·
·
·
2.接下来就是队列的问题

等等复习
·
·
·
3.最后要注意的就是狗的问题 因为每个狗都只会延时一次所以 要标记已经延时过的狗

所以我们在结构体中用了如下的声明方式

typedef struct node{    int x;//当前坐标    int y;    int dog[1000][2];//已经经过的有狗的坐标    int key[5];//手中已经有的钥匙    int door[5];//已经打开的门}node;

官方的题解用的是状态压缩 这是原始版

先回顾队列

队列是一种特殊的线性表(可暂时理解成数组),特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,也就是说,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
在队列这种数据结构中,最先插入的元素将是最先被删除的元素;反之最后插入的元素将是最后被删除的元素,因此队列又称为“先进先出”(FIFO—first in first out)的线性表。

简单来说队列就是如上图左侧只能进入 右侧只能出

队列的常用函数如下

q.empty()//判断是否为空队列 空为真q.push(a)将数据a压入队列q.front()返回队列的第一个元素 注意只是返回不是剔除q.size()返回当点队列里元素的个数q.pop()弹出第一个元素 直接扔掉q.back()返回队列队尾的值 仅仅是返回而不剔除

具体使用见下文

回顾BFS

先上标准的BFS模板题

HDU1253

上代码注释讲解

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<cmath>using namespace std;#define N 55int map[N][N][N];//这里用来存储地图int vis[N][N][N];//这里用来标记走过的路 不能重复int tx[] = { 1, -1, 0, 0, 0, 0 };//下面3个竖着看 表示能走的方向int ty[] = { 0, 0, 1, -1, 0, 0 };//如第一数列表示x方向前进一步 其他方向不动int tz[] = { 0, 0, 0, 0, 1, -1 };//这是BFS和DFS的核心步骤;int a, b, c, t, ans;struct node{//结构体用来保存当前的位置和当前的步数    int x;    int y;    int z;    int step;};int check(int i, int j, int k)//判断是否可行{    if (i<0 || j<0 || k<0 || i >= a || j >= b || k >= c || map[i][j][k])        return 0;    return 1;}int bfs(int x, int y, int z){    int i;    queue<node> Q;//声明一个队列 队列内的元素必须均是node类型的    node q, p;    p.x = x;    p.y = y;    p.z = z;    p.step = 0;    vis[x][y][z] = 1;    Q.push(p);//将初始的节点压入队列    while (!Q.empty())//如果队列不为空    {        p = Q.front();//p为当前队列的第一个元素        Q.pop();//将第一个元素弹出        if (p.x == a - 1 && p.y == b - 1 && p.z == c - 1 && p.step <= t)            return p.step;//找到就返回        for (i = 0; i < 6; i++)//分别代表上面的声明的6个方向        {            q = p;            q.x += tx[i];            q.y += ty[i];            q.z += tz[i];            if (!vis[q.x][q.y][q.z] && check(q.x, q.y, q.z))//判断是否走过 是否是墙            {                q.step++;//每走过一步 步数加一                vis[q.x][q.y][q.z] = 1;//标记走过                if (abs(q.x - a + 1) + abs(q.y - b + 1) + abs(q.z - c + 1) + q.step > t)                    continue;//这个if内的是一种剪枝的方法 可以不看这两行                Q.push(q);//将新的位置压入队尾            }        }    }    return -1;}int main(){    int cas;    scanf_s("%d", &cas);    while (cas--)    {        int i, j, k;        scanf_s("%d%d%d%d", &a, &b, &c, &t);//读取数据        memset(map, 0, sizeof(map));        memset(vis, 0, sizeof(vis));//清空两个数组        for (i = 0; i<a; i++)            for (j = 0; j<b; j++)                for (k = 0; k<c; k++)                    scanf_s("%d", &map[i][j][k]);读取        ans = bfs(0, 0, 0);        printf("%d\n", ans);    }    return 0;}

下面上原题代码

#include <iostream>#include <stdio.h>#include <string.h>#include <queue>#define INF 0xfffffffusing namespace std;typedef struct node{    int x,y,t;    int k,dog;}node;int fmin(int a,int b){return a<b?a:b;}int dirx[]={0,0,1,0,-1},diry[]={0,1,0,-1,0};int dogx[10],dogy[10],dogl;int n,TT;bool mark[105][105][20][64];char maze[105][105];int which_dog(int x,int y){//状态压缩 ……    for(int i=1;i<=dogl;++i)        if(x==dogx[i] && y==dogy[i]) return i;}void bfs(node s){    queue <node> q;    mark[s.x][s.y][s.k][s.dog]=true;    q.push(s);    while(!q.empty()){        s=q.front();        q.pop();        if(s.t>TT)continue;        if(maze[s.x][s.y]=='P'){            TT =fmin(TT,s.t);            continue ;        }        for(int i=1;i<=4;i++){            node w=s;            w.x+=dirx[i];            w.y+=diry[i];            w.t++;            if(w.x<1 || w.x>n || w.y<1 || w.y>n || maze[w.x][w.y]=='#') continue;            char c=maze[w.x][w.y];            if(c=='D'){//标记狗 状态压缩的方法                int j=which_dog(w.x,w.y);                if((w.dog&(1<<j))==0){                    w.dog |= (1<<j);                    w.t++;                }                if(!mark[w.x][w.y][w.k][w.dog]){                    q.push(w);                    mark[w.x][w.y][w.k][w.dog]=true;                }            }            else if(isdigit(c)){//函数作用 判断是否是数字                w.k |= (1<<(c-'1'));                if(!mark[w.x][w.y][w.k][w.dog]){//是数字标记 存入                    mark[w.x][w.y][w.k][w.dog]=true;                    q.push(w);                }            }            else if(islower(c)){                if((w.k & (1<<(c-'a'))) && (!mark[w.x][w.y][w.k][w.dog])){                   mark[w.x][w.y][w.k][w.dog]=true;                    q.push(w);                }            }            else if(!mark[w.x][w.y][w.k][w.dog]){                mark[w.x][w.y][w.k][w.dog]=true;                q.push(w);            }        }    }}int main(){    while(scanf("%d",&n)!=EOF){        node s;        memset(mark,false,sizeof(mark));        dogl=0;        for(int i=1;i<=n;i++){            scanf("%s",&maze[i][1]);            for(int j=1;j<=n;j++)                if(maze[i][j]=='O') s.x=i,s.y=j;                else if(maze[i][j]=='D') dogx[++dogl]=i,dogy[dogl]=j;        }        TT=INF;        s.k=0;        s.dog=0;        s.t=0;        bfs(s);        if(TT==INF )printf("GgSmd\n");        else printf("%d\n",TT);    }    return 0;}

这个代码是我照着重敲的 可能有错………………

0 0