两个bfs题:逃跑和奇怪的最短路

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个bfs题:逃跑和奇怪的最短路相关的知识,希望对你有一定的参考价值。

技术分享

技术分享

技术分享

bfs 搜索状态多加一维表示时间
vis[x][y][t]表示t时间能否到达点(x,y)
对于每个士兵,预处理出哪些时间哪些点是不可访问

这题看着提示瞎写一通结果过了。。恍恍惚惚

#include <cstdio>
#include <algorithm>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <queue>
#include <memory.h>
using namespace std;
int n,m,k,d;
char mat[105][105];
int vis[105][105][1005];
int dir[5][2]={-1,0,1,0,0,-1,0,1,0,0};
int ans=20000000;
struct point
{
    int x,y,time;
    point(int xx,int yy,int tt)
    {
        x=xx;
        y=yy;
        time=tt;
    }
};
void bfs(point po)
{
    queue<point> q;
    q.push(po);
    vis[po.x][po.y][po.time]=1;
    while(!q.empty())
    {
        point p=q.front();
        q.pop();
        if(p.x==n&&p.y==m)
        {
            ans=p.time;
            break;
        }
        for(int i=0;i<5;i++)
        {
            int nx=p.x+dir[i][0];
            int ny=p.y+dir[i][1];
            int ntime=p.time+1;
            if(nx<0||ny<0||nx>n||ny>m||vis[nx][ny][ntime]||ntime>d) continue;
            //在此处设置访问
            vis[nx][ny][ntime]=1;
            q.push(point(nx,ny,ntime));
        }
    }
}
bool cmp(int x,int y)
{
    return x>y;
}
void print()
{
    for(int k=0;k<=d;k++)
    {
        cout<<k<<"时刻:"<<endl;
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
            {
                cout<<vis[i][j][k]<<" ";
            }
            cout<<endl;
        }
    }
}
//bfs 搜索状态多加一维表示时间
//vis[x][y][t]表示t时间能否到达点(x,y)
//对于每个士兵,预处理出哪些时间哪些点是不可访问
void solve(char di,int t,int v,int x,int y)
{
    for(int i=0;i<d+1;i++)
        vis[x][y][i]=1;
    //上下左右
    if(di==N)
    {
        //i代表横坐标
        //从第一个射到的点开始
        for(int i=1;x-i*v>=0;i++)
        {
            //每隔一个周期这个点会再次被射到,即不能通过
            for(int j=i;j<=d;j+=t)
            {
                vis[x-i*v][y][j]=1;
            }
        }
    }
    else if(di==S)
    {
        for(int i=1;x+i*v<=n;i++)
        {
            for(int j=i;j<=d;j+=t)
            {
                vis[x+i*v][y][j]=1;
            }
        }
    }
    else if(di==W)
    {
        for(int i=1;y-i*v>=0;i++)
        {
            for(int j=i;j<=d;j+=t)
            {
                vis[x][y-i*v][j]=1;
            }
        }
    }
    else if(di==E)
    {
        for(int i=1;y+i*v<=m;i++)
        {
            for(int j=i;j<=d;j+=t)
            {
                vis[x][y+i*v][j]=1;
            }
        }
    }
    //print();
}

int main ()
{
    memset(vis,0,sizeof(vis));
    cin>>n>>m>>k>>d;
    char di;
    int t,v,x,y;
    for(int i=0;i<k;i++)
    {
        cin>>di>>t>>v>>x>>y;
        solve(di,t,v,x,y);
    }
    bfs(point(0,0,0));
    if(ans!=20000000) cout<<ans<<endl;
    else cout<<"Bad luck!";
    return 0;
}

 

技术分享

技术分享

技术分享

反向建图,2 遍 bfs。一遍 bfs,求出哪些点能到达终点,然后标记哪些点的所有出边都能到达终点,再一遍 bfs 的时候只访问标记过的点。

这题也是瞎写。。然后过了。。很迷

#include <cstdio>
#include <algorithm>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <queue>
#include <memory.h>
using namespace std;
int n,m,x,y,s,t;
int dir[4][2]={-1,0,1,0,0,-1,0,1};
int ans=-1;

//反向存储图
vector<int> mapp1[10005];
//正向存储图
vector<int> mapp2[10005];

//第一次bfs 筛选出能到达终点&&所有的出边指向的点都能到达终点的点
int vis1[10005];
//第二次bfs
int vis2[10005];

//存放能到达终点的点
vector<int> point_can1;
//存放能到达终点&&所有的出边指向的点都能到达终点的点
vector<int> point_can2;

//从终点反向搜索,先选出能到达终点的点
//再从中选出所有的出边指向的点都能到达终点的点
void bfs1(int s,int t)
{
    queue<int> q;
    q.push(t);
    vis1[t]=1;
    while(!q.empty())
    {
        int point=q.front();
        q.pop();
        for(int i=0;i<mapp1[point].size();i++)
        {
            int p=mapp1[point][i];
            if(!vis1[p])
            {
                vis1[p]=1;
                q.push(p);
                //记录能到达终点的点
                point_can1.push_back(p);
            }
        }
    }

    for(int i=0;i<point_can1.size();i++)
    {
        int flag=1;
        for(int j=0;j<mapp2[point_can1[i]].size();j++)
        {
            //如何这个点的出边不能走到终点则此点不可选
            if(!vis1[mapp2[point_can1[i]][j]])
            {
                flag=0;break;
            }
        }
        if(flag) point_can2.push_back(point_can1[i]);
    }
}
void bfs2()
{
    //如果起点无法到达 直接出
    if(count(point_can2.begin(),point_can2.end(),s)==0) return;
    queue<pair<int,int> > q;
    q.push(pair<int,int>(s,0));
    vis2[s]=1;
    while(!q.empty())
    {
        pair<int,int> point=q.front();
        q.pop();
        for(int i=0;i<mapp2[point.first].size();i++)
        {
            int next=mapp2[point.first][i];
            if(next==t)
            {
                ans=point.second+1;
                return;
            }
            //如果下一个点是合法点并且没有被访问过
            if(!vis2[next]&&count(point_can2.begin(),point_can2.end(),next)>0)
            {
                q.push(pair<int,int>(next,point.second+1));
                vis2[next]=1;
            }
        }
    }
}
int main ()
{
    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        cin>>x>>y;
        mapp2[x].push_back(y);
        mapp1[y].push_back(x);
    }
    cin>>s>>t;
    bfs1(s,t);
    bfs2();
    cout<<ans<<endl;
    return 0;
}

 



以上是关于两个bfs题:逃跑和奇怪的最短路的主要内容,如果未能解决你的问题,请参考以下文章

[bfs最短路] aw1076. 迷宫问题(bfs最短路+模板题)

[M最短路] lc1129. 颜色交替的最短路径(bfs最短路+拆点+拆边+好题)

leetcode之最短路径+记忆化dfs+bfs+动态规划刷题总结

题解——逃离僵尸岛(BFS+最短路+虚拟节点)

迷宫的最短路径问题(BFS)

leetcode 934. Shortest Bridge 最短的桥(中等)