bfs模板(优先队列)hdu1242&poj4115

hdu1242

题意:给一个字符地图,a代表要救的人,r代表起点,x代表士兵,.代表道路,走一次花一单位的时间,杀死一个士兵花一单位的时间。求出最少的时间,不能救到就输出Poor ANGEL has to stay in the prison all his life.

经典bfs,用优先队列,按照时间从小到大排序,小的优先级高

不知道为啥,用flag标记的就ac,直接在bfs结束时输出Poor ANGEL has to stay in the prison all his life.就wa

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<queue>
#include<map>
using namespace std;
char mp[205][205];
int m,n;
bool vis[205][205];
int dr[4][2]={1,0,-1,0,0,1,0,-1},flag;
struct node
{
    int x,y,cost;
    friend bool operator < (const node &a,const node &b)
    {
        return a.cost>b.cost;
    }
};//定义结构体排序
void bfs(int x,int y)
{
    node start;
    start.x=x;start.y=y;
    start.cost=0;
    priority_queue <node> q;
    q.push(start);
    while(!q.empty())
    {
        node now,nt;
        now=q.top();
        q.pop();
        if(mp[now.x][now.y]=='r')
        {
            printf("%d\n",now.cost);
            flag=0;
            break;
        }
        int nx,ny;
        for(int i=0;i<4;i++)
        {
            nx=dr[i][0]+now.x;
            ny=dr[i][1]+now.y;
            if(nx>=0&&nx<n&&ny>=0&&ny<m&&!vis[nx][ny]&&mp[nx][ny]!='#')
            {
                nt.x=nx;nt.y=ny;
                if(mp[nx][ny]=='.'||mp[nx][ny]=='r')
                {
                    nt.cost=now.cost+1;
                    q.push(nt);
                    vis[nx][ny]=1;
                }
                else if(mp[nx][ny]=='x')
                {
                    nt.cost=now.cost+2;
                    q.push(nt); 
                    vis[nx][ny]=1;                   
                }
            }
        }
    }
    //如果在这里输出搜不到的情况就是wa,这实在不懂
}
int main()
{
    int i,j,ans;
    while(scanf("%d%d",&n,&m)==2)
    {
        memset(vis,0,sizeof(vis));
        flag=1;
        for(i=0;i<n;i++)
        cin>>mp[i];
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                if(mp[i][j]=='a')//从a开始,因为有多个r,虽然从r开始也能过
                //但是这不能过第三个样例,这是个hdu的bug
                {
                    vis[i][j]=1;
                    bfs(i,j);
                }
            }
        }
        if(flag)printf("Poor ANGEL has to stay in the prison all his life.\n");
    }//要用flag标记
    return 0;
}

poj 4115

题意:

鸣人要去救被大蛇丸带走的佐助,*代表路,@是鸣人,+是佐助,#代表大蛇丸手下,鸣人有查克拉,1个查克拉可以弄死一个大蛇丸手下(不花时间),走一单位路花一单位时间,如果没有查克拉了,就不能走到有大蛇丸手下的地方。求最少要多少时间才能救出佐助,救不出就输出-1

本着对火影的热爱,想着bfs搜一遍就好,但是一直wa,我非常肯定我bfs已经没有bug了,可是又想不到哪里错了,开始的时候我直接写的普通bfs迷宫,如果走到了#,判断查克拉还有没有,如果有就把查克拉减一,再入队,如果没有就不能走,不入队。

这样写看起来没有问题,我想了很久也没有发现哪里错了。错的地方就在于查克拉,因为走到一个位置,位置和步数(这个状态)是没有问题的,问题在于怎么到这一步的,有可能有很多路都能到这一点,但是有一些路消耗的查克拉少,有的消耗得多,

那么如果选了消耗得多的路,(而且到了这个点,这个点就被标记了不能再走,那么就没有把其他消耗查克拉少的路加入队列)

就很可能救不了佐助。

其实没有什么特别的地方,但是在选择的时候,肯定先选步数少的,如果步数一样,要先选择查克拉多的,用优先队列对结构体进行排序就好

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
struct pos
{
    int x,y,t,step;//x,y代表位置,t剩余查克拉
    bool operator<(const pos temp)const
    {
        if(step==temp.step)return t<temp.t;
        //在步数相同的时候,先选查克拉多的
        return step>temp.step;
        //优先选择步数少的
    }
};
char mp[205][205];
bool vis[205][205];
int m,n,flag,T,ans;
int dr[4][2]={1,0,-1,0,0,1,0,-1};
void bfs(int x,int y)//bfs模板,毫无技巧可言
{
    pos st;
    priority_queue<pos>q;
    st.x=x;st.y=y;
    st.step=0;st.t=T;
    q.push(st);
    vis[x][y]=1;
    while(!q.empty())
    {
        pos now=q.top();
        q.pop();
        if(mp[now.x][now.y]=='+')
        {
            flag=1;
            ans=now.step;
            break;
        }
        for(int i=0;i<4;i++)
        {
            int nx,ny;
            nx=now.x+dr[i][0];
            ny=now.y+dr[i][1];
            if(nx>=0&&nx<n&&ny>=0&&ny<m&&!vis[nx][ny])
            {
                pos Next;
                Next.x=nx;Next.y=ny;
                Next.step=now.step+1;
                if(mp[nx][ny]=='#')
                {
                    if(now.t>0)
                    {
                        Next.t=now.t-1;
                        q.push(Next);
                        vis[nx][ny]=1;
                    }//当走到#,又没有查克拉的时候,不能走
                }
                else if(mp[nx][ny]!='#')
                {
                    Next.t=now.t;
                    q.push(Next);
                    vis[nx][ny]=1;
                }
            }
        }
    }
}
int main()
{
    int i,j;
    while(scanf("%d%d%d",&n,&m,&T)==3)
    {
        for(i=0;i<n;i++)
        scanf("%s",mp[i]);
        memset(vis,0,sizeof(vis));
        flag=0;
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                if(mp[i][j]=='@')
                {
                    bfs(i,j);
                    break;
                }
            }
        }
        if(flag)printf("%d\n",ans);
        else printf("-1\n");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值