hdoj 2128/hdu 2128 Tempter of the Bone II (附数据)

 好久没有更新空间了,上学期心思都花在同学身上了,结局十分悲摧大哭..目前转移注意力到acm上来.

 

队里在训练搜索 我这种水货也跟着打打酱油吧.

hdu 2128 Tempter of the Bone II

这个题应该是hdu1010的加强版吧

 

题意就是 地图上有个起点S 终点D 还有一些障碍物X和 1--9炸弹可以捡  doggie可以上下左右四个方向走 遇到障碍物如果有炸弹可以炸开 花费1秒钟

问走到出口最少时间

 

地图8x8 我没有试过深度优先搜索 比如迭代dfs

我直接用堆队列宽搜  时间小的在堆顶嘛

 

然后就是状态的判重

 

这题听他们说HDU数据很弱 所以好多错的方法都过了...

不知道别人怎么做的 说下我的方法

 

由于这个doggie地图上走来走去 会炸障碍物 会捡炸弹 所以会破坏地图

所以我们搜索的同时可能要保存地图

 

这里地图是8x8==64 我用的位压缩保存 unsigned long long  2^64-1 刚好64位

地图从上到下从左到右格子分别标记为0--n*m-1号

这样位与格子就对应起来了

 

未压缩里有意义的只有炸弹和障碍物的格子 因为其他格子不会变的

我的未压缩里 如果一个障碍物格子或者炸弹格子对应的为是0,说明没有走过,1则表示走过的.

 

这里unsigned long long数量有点大 不过是离散的 我用的红黑树map保存

 

map<ULL,int> visited[N][N];

visited[x][y][k] 表示到[x,y]这个点,地图状态为k的最小时间 如果后面也可以到这个状态 但时间比当前的时间要长 就不用继续搜索了.

 可能有的人会问这样时间复杂度够吗 乘了一个logM  我也不好说 这个有一定期望在里面 总的来说是过得去的 再说了 反正优先队列已经有了一个logM了 怕什么 正确率优先嘛...

 

我真不知道0ms是怎么出来的...

附点数据:

8 8
......XD
.XXXX..X
.XXXXX..
.XXXXXXX
.XXXXXXX
...4XXXX
XXXXXXX3
XXXXXXXS

38

 

6 5
S.XX1
X.1X1
XX.X.
XXXXX
XXXXX
XXXDX

17

 

6 6
S1XX3X
XXXXXX
2XXXXX
XXXXXX
XXXXXX
X1XDXX
29

 

5 6
S.XXXX
21..XX
XXXXXX
XXXXXX
3XXXDX

11

 

5 3
S..
1X.
XX.
...
XXD

6

 

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<map>

using namespace std;
typedef unsigned long long ULL;
const int MAXN = 8;
const int INF = 0x3fffffff;

char mapx[MAXN][MAXN];
map<ULL,int> visited[MAXN][MAXN];

int dir[4][2]=          //下 右 上 左 四个方向
{
    {1,0},
    {0,1},
    {-1,0},
    {0,-1}
};
int n,m;
int ai,aj,bi,bj;        //起点 终点

struct State
{
    int x,y,e;
    int time;
    ULL flg;
    State(int _x=0,int _y=0,int _e=0,int _time=0,ULL _flg=0)
    {x=_x;y=_y;e=_e;time=_time;flg=_flg;}

    bool operator < (const State & v) const     //小根堆
    {
        return time>v.time;
    }
};

void InputData()
{
    for(int i=0;i<n;i++)
    {
        while(getchar()!='\n');
        for(int j=0;j<m;j++)
        {
            mapx[i][j]=getchar();
            if(mapx[i][j]=='S')
                ai=i,aj=j;
            else
            if(mapx[i][j]=='D')
                bi=i,bj=j;
        }
    }
}
bool is_legal(int x,int y)
{
    if(x<0 || x>=n || y<0 || y>=m)
        return false;
    return true;
}
int Bfs()
{
    priority_queue<State> q;
    for(int i=0;i<MAXN;i++)
    {
        for(int j=0;j<MAXN;j++)
            visited[i][j].clear();
    }
    q.push(State(ai,aj,0,0,0));
    visited[ai][aj][0]=0;
    while(!q.empty())
    {
        State u=q.top();
        q.pop();
        if(u.time>visited[u.x][u.y][u.flg])
            continue;
        if(u.x==bi && u.y==bj)
            return u.time;
        for(int c=0;c<4;c++)
        {
            //产生下一格横纵坐标
            int nx=u.x+dir[c][0];
            int ny=u.y+dir[c][1];
            if(!is_legal(nx,ny))
                continue;
            int k=nx*m+ny;

            if(mapx[nx][ny]=='X')
            {
                if(!(u.flg & ((ULL)1<<k)))      //如果下一格没有走过
                {
                    map<ULL,int>::iterator it=visited[nx][ny].find(u.flg|((ULL)1<<k));
                    int num=(it==visited[nx][ny].end())?INF:it->second;
                    if(u.e>=1 && num>u.time+2)
                    {
                        visited[nx][ny][u.flg|((ULL)1<<k)]=u.time+2;
                        q.push(State(nx,ny,u.e-1,u.time+2,u.flg|((ULL)1<<k)));
                    }
                }
                else
                {
                    map<ULL,int>::iterator it=visited[nx][ny].find(u.flg);
                    int num=(it==visited[nx][ny].end())?INF:it->second;
                    if(num>u.time+1)
                    {
                        visited[nx][ny][u.flg]=u.time+1;
                        q.push(State(nx,ny,u.e,u.time+1,u.flg));
                    }
                }
            }
            else
            if(mapx[nx][ny]>='0' && mapx[nx][ny]<='9')
            {
                if(!(u.flg & ((ULL)1<<k)))
                {
                    map<ULL,int>::iterator it=visited[nx][ny].find(u.flg|((ULL)1<<k));
                    int num=(it==visited[nx][ny].end())?INF:it->second;
                    if(num>u.time+1)
                    {
                        visited[nx][ny][u.flg|((ULL)1<<k)]=u.time+1;
                        q.push(State(nx,ny,u.e+mapx[nx][ny]-'0',u.time+1,u.flg|((ULL)1<<k)));
                    }
                }
                else
                {
                    map<ULL,int>::iterator it=visited[nx][ny].find(u.flg);
                    int num=(it==visited[nx][ny].end())?INF:it->second;
                    if(num>u.time+1)
                    {
                        visited[nx][ny][u.flg]=u.time+1;
                        q.push(State(nx,ny,u.e,u.time+1,u.flg));
                    }
                }
            }
            else
            {
                map<ULL,int>::iterator it=visited[nx][ny].find(u.flg);
                int num=(it==visited[nx][ny].end())?INF:it->second;
                if(num>u.time+1)
                {
                    visited[nx][ny][u.flg]=u.time+1;
                    q.push(State(nx,ny,u.e,u.time+1,u.flg));
                }
            }
        }
    }
    return -1;
}
int main()
{
    while(scanf("%d %d",&n,&m) && (n || m))
    {
        InputData();
        int ans=Bfs();
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值