bryce1010专题——BFS

bryce1010专题——BFS

1. BFS模板题:

POJ3322
题意: Bloxorz是一个风靡世界的小游戏。Bloxorz的地图是一个N行M列的矩阵,每个位置可能是硬地(用.表示)、易碎地面(用E表示)、禁地(用#表示)、起点(用X表示)或终点(用O表示)。你的任务是操作一个112的长方体。这个长方体在地面上有两种放置形式,“立”在地面上(11的面接触地面)或者“躺”在地面上(12的面接触地面)。在每一步操作中,可以按上下左右四个键之一。按下之后,长方体向对应的方向沿着棱滚动90度。任意时刻,长方体不能有任何部位接触禁地(否则就会掉下去),并且不能立在易碎地面上(否则会因为压强太大掉下去)。X标识长方体的起始位置,地图上可能有一个X或者两个相邻的X。地图上唯一的一个O标识目标位置。求把长方体移动到目标位置(即立在O上)所需要的最少步数。如果无解,输出Impossible。在移动过程中,X和O标识的位置都可以看作是硬地被利用,3<=N,M<=500。

思路:
BFS,提前写好状态转换数组,减少代码量
(优秀代码见算法竞赛进阶P110)

#include 
#include 
#include 
#include 
#include 
#include 

inline void read(int &x)
{
    x = 0;char ch = getchar();
    char c = ch;
    while(ch > '9' || ch < '0')c = ch, ch = getchar();
    while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
    if(c == '-')x = -x;
}
inline int min(int a, int b){return a > b ? b : a;}
inline int max(int a, int b){return a > b ? a : b;}

const int INF = 0x3f3f3f3f; 
const int MAXN = 1000 + 10;
const int MAXM = 1000 + 10;

//0:一个点竖着,记录这个点的下标
//1:竖着躺 记录上面的那个点的坐标
//2:横着躺 记录左边的那个点的坐标 
const int dx[3][4] = {{-2,1,0,0},{-1,2,0,0},{0,0,-1,1}}; 
const int dy[3][4] = {{0,0,-2,1},{0,0,-1,1},{-1,2,0,0}};
const int dz[3][4] = {{1,1,2,2},{0,0,1,1},{0,0,2,2}};

char g[MAXN][MAXM];01BFS+思维】Codeforces Round #516 D. Labyrinth
题意:
给出一个迷宫,限定能往左走和往右走的次数分为为l,r,上下走不限,迷宫中能走的范围最大时多少格子?

思路:
采用双端队列,BFS的时候优先上下走放在双端队列首部,左右走放在队列尾部,这样可以保证走的方法最优。
--------------------- 
作者:bryce1010 
来源:CSDN 
原文:https://blog.csdn.net/Fire_to_cheat_/article/details/83067270?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!
int n,m,sx,sy,sz,ex,ey;

struct Point
{
    int x,y,z,step;
    Point(){}
    Point(int _x, int _y, int _z, int _step){x = _x;y = _y;z = _z;step = _step;}
};

std::queue<Point> q;
int b[MAXN][MAXM][4];

int Isok(Point a)
{
    if(a.z == 0 && !(a.x > n || a.x < 1 || a.y > m || a.y < 1) && !b[a.x][a.y][a.z] && g[a.x][a.y] != 'E' && g[a.x][a.y] != '#')return 0;
    if(a.z == 1 && !(a.x < 1 || a.x + 1 > n || a.y < 1 || a.y > m) && !b[a.x][a.y][a.z] && g[a.x][a.y] != '#' && g[a.x + 1][a.y] != '#')return 0;
    if(a.z == 2 && !(a.x < 1 || a.x > n || a.y < 1 || a.y + 1 > m) && !b[a.x][a.y][a.z] && g[a.x][a.y] != '#' && g[a.x][a.y + 1] != '#')return 0;
    return 1;
}

int bfs()
{
    memset(b, 0, sizeof(b));
    while(q.size())q.pop();
    q.push(Point(sx, sy, sz, 0));
    Point now;
    b[sx][sy][sz] = true;
    while(q.size())
    {
        now = q.front();q.pop();
        for(int i = 0;i < 4;++ i)
        {
            Point tmp;
            tmp = Point(now.x + dx[now.z][i],now.y + dy[now.z][i], dz[now.z][i], now.step + 1);
            if(Isok(tmp)) continue;
            if(tmp.x == ex && tmp.y == ey && !tmp.z)return tmp.step;
            q.push(tmp);
            b[tmp.x][tmp.y][tmp.z] = 1;
        }
    }
    return -1;
}

int main()
{
    while (scanf("%d %d", &n, &m) && n)
    {
        for(int i = 1;i <= n;++ i)
            scanf("%s", g[i] + 1);
        for (int i = 1;i <= n;++ i)
        {
            for (int j = 1;j <= m;++ j)
                if (g[i][j] == 'O')
                    ex = i,ey = j;
                else if (g[i][j] == 'X' && g[i + 1][j] == 'X')
                {
                    sx = i,sy = j;
                    g[i + 1][j] = '.';
                    sz = 1;
                }
                else if(g[i][j] == 'X' && g[i][j + 1] == 'X')
                {
                    g[i][j + 1] = '.';
                    sx = i,sy = j;
                    sz = 2;
                }
                else if(g[i][j] == 'X')
                {
                    sx = i,sy = j;
                    sz = 0;
                }
        }
        int ans = bfs();
        if(ans == -1)puts("Impossible");
        else printf("%d\n", ans);
    }
    return 0;
}

2. flood-fill 问题

CH2501
题意:
给定一个N行M列的01矩阵 A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
dist(A[i][j],A[k][l])=|i-k|+|j-l|

输出一个N行M列的整数矩阵B,其中:
B[i][j]=min(1≤x≤N,1≤y≤M,A[x][y]=1)⁡{dist(A[i][j],A[x][y])}
即求与每个位置曼哈顿距离最近的1
N,M≤1000。

思路:
采用BFS,flood-fill就是最短距离

#include
using namespace std;
#define ll long long 
const int MAXN=1e3+10;

const int dx[4]={0,0,-1,1};
const int dy[4]={1,-1,0,0};

char s[MAXN][MAXN];
int d[MAXN][MAXN];
queue<pair<int,int> >que;

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>s[i][j];
		}
	}
	memset(d,-1,sizeof(d));
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(s[i][j]=='1')
			{
				que.push(make_pair(i,j));
				d[i][j]=0;
			}
		}
	}
	pair<int,int>now,next;
	while(!que.empty())
	{
		now=que.front();que.pop();
		for(int k=0;k<4;k++)
		{
			next.first=now.first+dx[k];
			next.second=now.second+dy[k];
			if(next.first<1||next.second>m||next.first>n||next.second<1)
				continue;
			if(d[next.first][next.second]==-1)
			{
				d[next.first][next.second]=d[now.first][now.second]+1;
				que.push(next);
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cout<<d[i][j]<<" ";
		}
		cout<<endl;
	}
	cout<<endl;
	return 0;
}

【01BFS+思维】Codeforces Round #516 D. Labyrinth

题意:
给出一个迷宫,限定能往左走和往右走的次数分为为l,r,上下走不限,迷宫中能走的范围最大时多少格子?

思路:
采用双端队列,BFS的时候优先上下走放在双端队列首部,左右走放在队列尾部,这样可以保证走的方法最优。

#include
using namespace std;

#define ll long long
const int MAXN=2000+10;

//01BFS
//左右走的放在队列首部,上下走的放在队列尾部
char s[MAXN][MAXN];
int n,m;
struct Node
{
    int X,Y,l,r;
    Node(){}
    Node(int _X,int _Y,int _l,int _r):X(_X),Y(_Y),l(_l),r(_r){}
};
deque<Node>que;
bool vis[MAXN][MAXN];
int dirx[4]={1,-1,0,0};
int diry[4]={0,0,-1,1};



int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    int r,c;
    int x,y;
    cin>>r>>c;
    cin>>x>>y;
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>s[i][j];
    Node now=Node(r,c,x,y);
    que.push_back(now);
    while(!que.empty())
    {
        now=que.front();que.pop_front();
        if(vis[now.X][now.Y]||now.l<0||now.r<0)continue;
        vis[now.X][now.Y]=1;ans++;
        for(int i=0;i<4;i++)
        {
            int nextx=now.X+dirx[i],nexty=now.Y+diry[i];
            if(nextx<1||nextx>n||nexty<1||nexty>m||s[nextx][nexty]=='*')continue;
            if(i==0||i==1)//up down
            {
                que.push_front(Node(nextx,nexty,now.l,now.r));
            }
            else if(i==2)//left
            {
                que.push_back(Node(nextx,nexty,now.l-1,now.r));
            }
            else if(i==3)
            {
                que.push_back(Node(nextx,nexty,now.l,now.r-1));
            }
        }
    }
    cout<<ans<<endl;



    return 0;
}

你可能感兴趣的:(1.8,ACM之路之搜索,1.8.1,BFS,1.1)