两个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;
}
时间: 2024-10-12 21:50:57

两个bfs题:逃跑和奇怪的最短路的相关文章

FZU 2196 Escape (两次BFS)

[题目链接]:click here~~ [题目大意]: Description 小明进入地下迷宫寻找宝藏,找到宝藏后却发生地震,迷宫各处产生岩浆,小明急忙向出口处逃跑.如果丢下宝藏,小明就能迅速离开迷宫,但小明并不想轻易放弃自己的辛苦所得.所以他急忙联系当程序员的朋友你(当然是用手机联系),并告诉你他所面临的情况,希望你能告诉他是否能成功带着宝藏逃脱. Input 有多组测试数据. 每组测试数据第一行是一个整数T,代表接下去的例子数.(0<=T<=10) 接下来是T组例子. 每组例子第一行是两

uva11624 - Fire! 两次bfs

题目链接 Problem B: Fire! Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of the maze neglected to create a fire escape plan. Help Joe escape the maze. Given Joe's location in the maze and which squares of the

求树的直径【两遍BFS】

两遍BFS.从任意一个点出发,第一遍可以找到直径的一端,从这端出发即可找到另外一端. 证明:从U点出发,到达V[画个图便清晰了] 1.如果U在直径上,则V一定是直径的一个端点. 2.如果U不在直径上.U,V线一定和直径有交点(如果没有交点,从U引一条路到直径交于U'.[反证]).有交点则V一定是直径另一端. 代码:[举例] int path(int x){ //从x出发,求直径 mem(vis,-1); while(!Q.empty()) Q.pop(); Q.push(x); vis[x]=0

URAL 1145. Rope in the Labyrinth(两次BFS啊 )

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1145 1145. Rope in the Labyrinth Time limit: 0.5 second Memory limit: 64 MB A labyrinth with rectangular form and size m × n is divided into square cells with sides' length 1 by lines that are paralle

UVa 1599 Ideal Path (两次BFS)

题意:给出n个点,m条边的无向图,每条边有一种颜色,求从结点1到结点n颜色字典序最小的最短路径. 析:首先这是一个最短路径问题,应该是BFS,因为要保证是路径最短,还要考虑字典序,感觉挺麻烦的,并不好做,事实用两次BFS, 第一次是倒序BFS,目的是得到从结点 i 到结点n的最短距离,然后再从第一个点开始到最后一个,要保证在查找时,每经过一点要让d值恰好减少1, 直到终点,这也是一个BFS,因为这个字典序在某个结点是一样的,所以是两个BFS,我超时了好几次,因为少写了一个vis, 一定要细心,

hihocoder#1050 : 树中的最长路(树中最长路算法 两次BFS找根节点求最长+BFS标记路径长度+bfs不容易超时,用dfs做TLE了)

#1050 : 树中的最长路 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中,小Ho发现他不仅仅可以拼凑成一棵二叉树!还可以拼凑成一棵多叉树——好吧,其实就是更为平常的树而已. 但是不管怎么说,小Ho喜爱的玩具又升级换代了,于是他更加爱不释手(其实说起来小球和木棍有什么好玩的是吧= =).小Ho手中的这棵玩具树现在由N个小球和N-1根木棍拼凑而成,这N个小球都被小Ho标上了不

hdu-2612 两次bfs

http://acm.hdu.edu.cn/showproblem.php?pid=2612 两次bfs, 记录到每个KFC的最短时间.选取最短时间. #include <stdio.h> #include <iostream> #include <string> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #inc

逛园子,看到个练习题,小试了一把(淘宝ued的两道小题)

闲来无事,逛园子,充充电.发现了一个挺有意思的博文,自己玩了一把. 第一题:使用 HTML+CSS 实现如图布局,border-widht 1px,一个格子大小是 60*60,hover时候边框变为橘红色(兼容IE6+,考虑语义化的结构) 效果图: 简单分析一下: 使用伪类 :hover的时候相对定位 改变z-index, 代码如下: 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta c

逆向+两次bfs(UVA 1599)

为什么都说简单好想咧.坦白从宽看了人家的代码,涨了好多姿势,, http://blog.csdn.net/u013382399/article/details/38227917 被一个细节坑了.. 2147483647是0x7fffffff啊啊啊,7个f!!! 1 #include <iostream> 2 #include <sstream> 3 #include <cstdio> 4 #include <cstring> 5 #include <c