fzuoj 2186 小明的迷宫 bfs+bfs状压+剪枝

来源:互联网 发布:mac怎么压缩rar 编辑:程序博客网 时间:2024/05/21 17:21

Problem 2186 小明的迷宫

Accept: 137    Submit: 453
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

小明误入迷宫,塞翁失马焉知非福,原来在迷宫中还藏着一些财宝,小明想获得所有的财宝并离开迷宫。因为小明还是学生,还有家庭作业要做,所以他想尽快获得所有财宝并离开迷宫。

Input

有多组测试数据。

每组数据第一行给出两个正整数n,m(0<n,m<=100)。代表迷宫的长和宽。

接着n行,每行m个整数。正数代表财宝(财宝的个数不超过10);负数代表墙,无法通过;0代表通道。

每次移动到相邻的格子,所花费的时间是1秒。小明只能按上、下、左、右四个方向移动。

小明的初始位置是(1,1)。迷宫的出口也在(1,1)。

Output

输出获得所有财宝并逃出迷宫所花费的最小时间,如果无法完成目标则输出-1。

Sample Input

3 30 0 00 100 00 0 02 21 11 1

Sample Output

44
思路:看了看网上写的都是用 bfs求最短路加dp的。我这里是用两个bfs做的。
   两个bfs ,一个bfs 求(1,1)点到其他点的最短路径,还有一个 搜索。但是要注意一点的就是 这组数据 
状压不懂得可以先看这里:

http://blog.csdn.net/lw277232240/article/details/75004165  有详细介绍状压

3 3
1 2 3
4 5 6
7 8 9
,这里搜到的最短路找完宝藏,有几处都是为8  所以要加上后面的dis【x】【y】,进行判断,要一个最短的。
还有一种数据就是起点是负数,这点也要考虑。
详细的见代码;

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<queue>using namespace std;#define INF 999999999struct node{    int x,y;};struct node1{    int x,y;    int step;    int k;};int dis[101][101];bool vis[101][101][1025];int n,m;int dir[4][2]={1,0,-1,0,0,1,0,-1};int map[101][101];int count;int ans;int jude(int x,int y){    if(x<1||x>n||y<1||y>m) return 0;    return 1;}void bfs(){   queue<node>q;    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            dis[i][j]=INF;        }    }    node a={1,1};    dis[1][1]=0;    q.push(a);    while(!q.empty())    {        a=q.front();        q.pop();        for(int i=0;i<4;i++)        {            int xx=a.x+dir[i][0];            int yy=a.y+dir[i][1];            if(!jude(xx,yy)) continue;            if(map[xx][yy]<0) continue;            if(dis[xx][yy]>dis[a.x][a.y]+1)            {                dis[xx][yy]=dis[a.x][a.y]+1;                node b={xx,yy};                q.push(b);            }        }    }}void bfs2(){  memset(vis,0,sizeof(vis));    queue<node1>q;    node1 a={1,1,0,0};    int end1=(1<<(count-1))-1;    if(map[1][1]>0)    {        a.k=a.k|1<<(map[1][1]-1);    }    vis[a.x][a.y][a.k]=1;    q.push(a);    while(!q.empty())    {        a=q.front();        q.pop();        if(a.k==end1)//全都找完了继续执行,怕有可能有比他小的dis【a.x】【a.y】;        {          if(ans>a.step+dis[a.x][a.y])                   ans=a.step+dis[a.x][a.y];         continue ;        }        if(a.step+dis[a.x][a.y]>ans) continue;//当当前路径加上 跟 当前点到1,1点的最短路径大于ans 不进入循环。        for(int i=0;i<4;i++)        {   node1 b=a;            b.x+=dir[i][0];            b.y+=dir[i][1];            b.step=a.step+1;            if(!jude(b.x,b.y)) continue;            if(map[b.x][b.y]<0) continue;            if(map[b.x][b.y]>0)            {   int kk=b.k|(1<<(map[b.x][b.y]-1));                if(vis[b.x][b.y][kk]) continue;                vis[b.x][b.y][kk]=1;                b.k=kk;                q.push(b);            }            else            {                if(vis[b.x][b.y][b.k])                      continue;                vis[b.x][b.y][b.k]=1;                q.push(b);            }        }    }}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {   count=1;        memset(map,0,sizeof(map));        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&map[i][j]);                if(map[i][j]>0)                {                    map[i][j]=count++;                }            }        }        if(map[1][1]<0)        {            printf("-1\n");            continue;        }        bfs();//求1.1到其他点的最短路        int flag=0;        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)               if(map[i][j]>0&&dis[i][j]==INF)//当有宝藏的地方求不出最短路直接输出-1;               {                   printf("-1\n");                   flag=1;               }        }        if(flag) continue;        ans=INF;        bfs2();        printf("%d\n",ans);        }}


原创粉丝点击