POJ 2049 Finding Nemo

某周日,回寝室路上,让室友帮忙找个东西,室友问找啥,答曰:Nemo。

1、百练上只有不到一半的通过率还是有点恐怖的,这道题让nemo他爹找nemo,让我想到之前的走迷宫,于是想到用广度优先搜索的办法,只不过把原来的queue改成了priority——queue,让走过的doors数量最少的借点排在最前面,这样第一个走出迷宫范围的结点就一定最优解(我是每次从队列中取出元素之后再判断是否在迷宫外面,而不是在搜索的时候直接进行判断,后者的方法应该是错误的)。

2、坑点在于nemo的初始位置可以是在迷宫外面的,因此在最刚开始入队的时候要先进行一次判断,如果在迷宫外面直接输出0即可。

3、另外卡了我将近一个小时的点在于priority_queue的数据排列顺序,top()的元素是最大的一个元素!也就是说我们在对运算符进行重载的时候要把符号正好反过来!记忆的方法是权重最大的符号要在最前面!

4、这道题也可以当作图的题目来做,把整个迷宫看作一个图,如果两个节点之间是门,距离就视为1,没有门距离就视为1,有墙壁则没有通路,只是一个想法,不知道有哪位大神可以实现,感觉这道题放在图的图题目里面还是很坑爹的。

#include<iostream>
#include<limits.h>
#include<memory.h>
#include<cstdio>
#include<cstring>
#include<memory.h>
#include<queue>
using namespace std;

#define maxn 220

struct maze_node{
    bool uw,rw;
    bool ud,rd;
};

struct node{
    float x,y;
    int doors;
}; 

bool operator < (node a,node b){
    return a.doors > b.doors;
}

maze_node maze[maxn][maxn] ={0};
bool used[maxn][maxn]={0};

bool init(){
    memset(used,0,sizeof(used));
    memset(maze,0,sizeof(maze));
    int W,D;
    int x,y,dir,len;
    scanf("%d%d",&W,&D);
    if(W==-1&&D==-1)
        return false;
    while(W--){
        scanf("%d%d%d%d",&x,&y,&dir,&len); 
        if(dir){
            for(int i=0;i<len;++i){
                maze[x][y+i].uw = 1;
            }
        }
        else{
            for(int i=0;i<len;++i){
                maze[x+i][y].rw = 1;
            }
        }
    }
    while(D--){
        scanf("%d%d%d",&x,&y,&dir);
        if(dir){
            maze[x][y].ud = 1;
            maze[x][y].uw = 0;
        }
        else{
            maze[x][y].rd = 1;
            maze[x][y].rw = 0;
        }
    }
    return true;
}

int main(){
    while(init()){
        float _x,_y;
        cin>>_x>>_y;
        if(_x<1.0||_x >199.0||_y<1.0||_y>199.0){
            cout<<0<<endl;
            continue;
        }
        node temp;
        temp.x = _x;
        temp.y = _y;
        temp.doors = 0;
        priority_queue<node> q;
        used[int(_x)][int(_y)] = 1;
        q.push(temp);
        bool find = false;
        while(q.size()){
            temp = q.top();
            q.pop();
            //cout<<temp.x<<' '<<temp.y<<endl;
            if(temp.x<1.0||temp.x>199.0||temp.y<1.0||temp.y>199.0){
                find = true;
                break;
            }
            int ix = (int)temp.x;
            int iy = (int)temp.y;
            used[ix][iy] = 1;
            if(!maze[ix][iy].uw && !used[ix-1][iy]){
                int td = temp.doors;
                if(maze[ix][iy].ud)
                    td++;
                node ins;
                ins.x = temp.x-1.0;
                ins.y = temp.y;
                ins.doors = td;
                q.push(ins);
            }
            if(!maze[ix][iy].rw && !used[ix][iy-1]){
                int td = temp.doors;
                if(maze[ix][iy].rd)
                    td++;
                node ins;
                ins.x = temp.x;
                ins.y = temp.y-1.0;
                ins.doors = td;
                q.push(ins);
            }
            if(!maze[ix+1][iy].uw && !used[ix+1][iy]){
                int td = temp.doors;
                if(maze[ix+1][iy].ud)
                    td++;
                node ins;
                ins.x = temp.x+1.0;
                ins.y = temp.y;
                ins.doors = td;
                q.push(ins);
            }
            if(!maze[ix][iy+1].rw && !used[ix][iy+1]){
                int td = temp.doors;
                if(maze[ix][iy+1].rd)
                    td++;
                node ins;
                ins.x = temp.x;
                ins.y = temp.y+1.0;
                ins.doors = td;
                q.push(ins);
            }
        }
        if(find){
            cout<<temp.doors<<endl;
        }
        else{
            cout<<"-1"<<endl;
        }
    }
    //system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值