hrbust 1286/哈理工oj 1286 迷宫与宝藏【较难bfs】

来源:互联网 发布:java获取本地磁盘文件 编辑:程序博客网 时间:2024/05/23 10:05

迷宫与宝藏Time Limit: 2000 MSMemory Limit: 65536 KTotal Submit: 141(26 users)Total Accepted: 31(20 users)Rating: Special Judge: NoDescription机器人要在一个矩形迷宫里行动(不能原地停留,只能走向上///右),每移动一格花费1个单位时间。

迷宫有以下几种元素:

* 机器人的起点

# 墙。机器人不能走过这些格子

. 平地。机器人可以在上面自由行走

0-9 宝藏。当机器人走到此处会立刻获得该数字相应的宝藏,宝藏不会消失,可以反复获取(但不能停留)

若机器人要恰好获得总和为x的宝藏,它最少需要多少时间?

Input第一行输入任务数量T, 接下来有T个任务

每块第一行有两个整数, n(0 <
100), m(0 < 100), 表示迷宫有n+1行和m+1

接下来n行输入迷宫

最后一行输入你要收集的宝藏的总价值x(x  100)Output对于每个任务,输出最少花费的时间,如果完成不了该任务则输出-1Sample Input3

2 3

1.#2

#..#

*.#.

3

2 3

2.#2

#..#

*.#.

5

2 3

2.#2

#.3#

*.#.

5Sample Output8

-1

6


做过不少这样的带着宝贝走的图搜的题、可惜这个题卡时间卡的太狠、剪枝无果、换思路、卡内存、优化代码、无果。如果是条件再放松一点点、这个题就好A多了、真的是一道很好的题目、卡时间,数据,内存具备、而且还有一个坑点、这里一会说(虽然找到了,但是还是没能AC)、最后还是看的大牛代码,找到了最终优化的方法、

首先呢,这里的路是可以重复行走的,但是行走重复的时候一定要保证身上带的东西的数量不同,要不然没有重复走这个路的必要、所以这里vis数组是三维的

分别存三个值,x,y,v(宝藏的价值)、

然后就bfs遍历就行了、优化几个小小的点:

1.起始点要注意是可以重复行走的、

2.如果当前走到的地方的宝藏数量大于了目标量,continue;

3.不用优先队列会超时、用了优先队列会超内存、、、、、妈了个巴子,不让人过个好年,好歹也是除夕,能不能愉快的玩耍了;

然后贴上我的思路的代码,一会和大牛的对比:

#include<stdio.h>#include<string.h>#include<queue>using namespace std;struct zuobiao{    int x,y,output;    int cur;    /*friend bool operator <(zuobiao a,zuobiao b)    {        return a.cur>b.cur;    }*/}now,nex;char  a[101][101];int vis[101][101][101];int fx[4]={0,0,1,-1};int fy[4]={1,-1,0,0};int n,m;int mubiao;void bfs(int x,int y){    queue<zuobiao >s;    //priority_queue<zuobiao>s;    memset(vis,0,sizeof(vis));    vis[0][x][y]=1;    now.x=x;    now.y=y;    now.output=0;    now.cur=0;    s.push(now);    while(!s.empty())    {        now=s.front();        s.pop();        for(int i=0;i<4;i++)        {            nex.x=now.x+fx[i];            nex.y=now.y+fy[i];            nex.output=now.output;            nex.cur=now.cur;            if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&vis[nex.output][nex.x][nex.y]==0&&a[nex.x][nex.y]!='#')            {                if(a[nex.x][nex.y]=='.')                {                    nex.cur++;                    vis[nex.output][nex.x][nex.y]=1;                    s.push(nex);                }                if(a[nex.x][nex.y]>='0'&&a[nex.x][nex.y]<='9')                {                    nex.cur++;                    nex.output+=a[nex.x][nex.y]-'0';                    //printf("%d\n",nex.output);                    if(nex.output==mubiao)                    {                        printf("%d\n",nex.cur);                        return ;                    }                    if(nex.output>mubiao)                    continue;                    vis[nex.output][nex.x][nex.y]=0;                    s.push(nex);                }            }        }    }    printf("-1\n");    return ;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d %d%",&n,&m);        n++;        m++;        int x,y;        for(int i=0;i<n;i++)        {            scanf("%s",a[i]);            for(int j=0;j<m;j++)            {                if(a[i][j]=='*')                {                    x=i;                    y=j;                    a[i][j]='.';                }            }        }        scanf("%d",&mubiao);        if(mubiao==0)        {            printf("0\n");            continue;        }        bfs(x,y);    }}


以上是我的代码和简单叙述的思路、可惜怎么做都不能AC掉、水平实力还是不够啊....................T T

然后我们来说大牛的代码:大牛博客传送门:http://www.cnblogs.com/-hsz/archive/2012/11/09/2762050.html

首先,他的思路是这样的:把*和.都变成0

        int x,y;        for(int i = 0; i < n; i++)        {            scanf("%s",map[i]);            for(int j=0; j<m; j++)            {                if(map[i][j]=='*')                {                    map[i][j]='0';                    x=i;                    y=j;                }                if(map[i][j]=='.')                {                    map[i][j]='0';                }            }        }

然后考虑时间最优,这里咱俩的做题思路是一样的,但是我的超内存、(因为我的队列里边存的东西太多了、剪枝无果)他的没有,他是怎么做的呢?

他用一个vis【】【】【】表示:行,列,价值,记录最小步数。那么他是如何保证是最小步数的呢?

我们对应代码来看:

int vis[101][101][101]; //行,列,价值。vis记录最小步数。首先对他初始化为INT_MAX(其实初始化足够大就行,不用这么完美)char map[101][101];int n, m, mubiao;struct zuobiao{    int x, y, v;}now,nex;int fx[4]={0,0,1,-1};int fy[4]={1,-1,0,0};int bfs(int x,int y){    now.x=x;    now.y=y;    now.v=0;    vis[now.x][now.y][now.v] = 0;    queue<struct zuobiao> s;    s.push(now);//起点入队    while(!s.empty())    {        struct zuobiao now=s.front();        s.pop();        for(int i = 0; i < 4; i++)        {            nex.x = now.x + fx[i];            nex.y = now.y + fy[i];            if(nex.x >= 0 && nex.x < n && nex.y >= 0 && nex.y < m && map[nex.x][nex.y] != '#')//符合条件的走向            {                nex.v = now.v + map[nex.x][nex.y] - '0';//宝藏入身、                if(nex.v == mubiao) return vis[now.x][now.y][now.v] + 1;//如果达到了目标数,输出                if(nex.v > mubiao) continue;//剪枝                if(vis[nex.x][nex.y][nex.v] > vis[now.x][now.y][now.v] + 1)//这里注意 ,很完美的语句,既达到了优先队列的效果(但是也不能说完全一样),也达到了时间数组的作用、注意初始化很大、                {                    vis[nex.x][nex.y][nex.v] = vis[now.x][now.y][now.v] + 1;                    s.push( nex );                }            }        }    }    return -1;}
然后上完整的AC代码:

#include<stdio.h>#include<limits.h>#include<string.h>#include<queue>using namespace std;int vis[101][101][101]; //行,列,价值。vis记录最小步数。char map[101][101];int n, m, mubiao;struct zuobiao{    int x, y, v;}now,nex;int fx[4]={0,0,1,-1};int fy[4]={1,-1,0,0};int bfs(int x,int y){    now.x=x;    now.y=y;    now.v=0;    vis[now.x][now.y][now.v] = 0;    queue<struct zuobiao> s;    s.push(now);    while(!s.empty())    {        struct zuobiao now=s.front();        s.pop();        for(int i = 0; i < 4; i++)        {            nex.x = now.x + fx[i];            nex.y = now.y + fy[i];            if(nex.x >= 0 && nex.x < n && nex.y >= 0 && nex.y < m && map[nex.x][nex.y] != '#')            {                nex.v = now.v + map[nex.x][nex.y] - '0';                if(nex.v == mubiao) return vis[now.x][now.y][now.v] + 1;                if(nex.v > mubiao) continue;                if(vis[nex.x][nex.y][nex.v] > vis[now.x][now.y][now.v] + 1)                {                    vis[nex.x][nex.y][nex.v] = vis[now.x][now.y][now.v] + 1;                    s.push( nex );                }            }        }    }    return -1;}int main(){    int T;    scanf("%d", &T);    while( T-- )    {        scanf("%d %d", &n, &m);        n++;        m++;        for(int i = 0; i < n; i++)        {            for(int j = 0; j < m; j++)            {                for(int k = 0; k < 101; k++)                {                    vis[i][j][k] =0x1f1f1f1f;                }            }        }        int x,y;        for(int i = 0; i < n; i++)        {            scanf("%s",map[i]);            for(int j=0; j<m; j++)            {                if(map[i][j]=='*')                {                    map[i][j]='0';                    x=i;                    y=j;                }                if(map[i][j]=='.')                {                    map[i][j]='0';                }            }        }        scanf("%d", &mubiao);        if(mubiao == 0)        {            printf("0\n");        }        else        {            printf("%d\n", bfs(x,y));        }    }    return 0;}









0 0
原创粉丝点击