POJ - 3322 Bloxorz I(bfs+状态设计)

题目链接:点击查看

题目大意:模拟Bloxorz小游戏找出最优解,简单说一下规则,给出一个n*m的矩阵,其中,"#"代表墙,"X"代表起点,"O"代表终点,"E"代表脆弱道路,即承受不住立着的方块,"."代表普通道路

题目分析:因为方块总共有三种状态:立着(占1格)、竖着(占2格)、横着(占2格),我们可以将占两个的两个状态压缩到一格中,竖着的(上下分布)我们规定有效方格在上面,横着的(左右分布)我们规定有效方格在左面,在转移状态时,立着的状态可以直接判断转移,其余两种状态需要判断两个方格是否同时满足条件才可以进行转移,我们在储存状态时用的结构体包含了四个变量:x,y,flag,step,分别代表横坐标,纵坐标,状态,和步数,而每种情况转移时都有4种不同的方案,所以方向函数需要写三个,并且每次转移时需要根据当前的状态分类讨论,细心一点认真写一下bfs就能A了,具体的细节写在代码中了,上代码:

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
using namespace std;
   
typedef long long LL;
  
const int inf=0x3f3f3f3f;
  
const int N=510;

char maze[N][N];

bool vis[N][N][3];

int n,m,ans;
//规定立着的状态为0,横着的状态为1,竖着的状态为2
const int b0[4][2]={0,-2,-2,0,0,1,1,0};//立着 flag=0 1,2,1,2

const int b1[4][2]={1,0,-1,0,0,-1,0,2};//横着 flag=1 1,1,0,0

const int b2[4][2]={0,-1,0,1,-1,0,2,0};//竖着 flag=2 2,2,0,0

struct Node
{
	int x,y,step,flag;
	Node(int X,int Y,int STEP,int FLAG)
	{
		x=X;
		y=Y;
		step=STEP;
		flag=FLAG;
	}
};

bool check(int x,int y)
{
	if(x<0||y<0||x>=n||y>=m)
		return false;
	return true;
}

bool bfs()
{
	memset(vis,false,sizeof(vis));
	queue<Node>q;
	for(int i=0;i<n;i++)//找一下起点
		for(int j=0;j<m;j++)
			if(maze[i][j]=='X')
			{
				if(check(i,j+1)&&maze[i][j+1]=='X')//如果起点是横着两个X
				{
					q.push(Node(i,j,0,1));
					vis[i][j][1]=true;
				}
				else if(check(i+1,j)&&maze[i+1][j]=='X')//如果起点是竖着两个X
				{
					q.push(Node(i,j,0,2));
					vis[i][j][2]=true;
				}
				else//如果起点是立着的一个X
				{
					q.push(Node(i,j,0,0));
					vis[i][j][0]=true;
				}
				goto start;//用goto函数跳出两层for循环
			}
start:
	while(!q.empty())
	{
		Node cur=q.front();
		q.pop();
//		cout<<cur.x<<' '<<cur.y<<endl;
		if(maze[cur.x][cur.y]=='O'&&cur.flag==0)
		{
			ans=cur.step;
			return true;
		}
		if(cur.flag==0)//若当前状态立着
		{
			for(int i=0;i<4;i++)
			{
				int xx=cur.x+b0[i][0];
				int yy=cur.y+b0[i][1];
				if(i==0||i==2)//flag=1
				{
					if(!check(xx,yy)||!check(xx,yy+1)||vis[xx][yy][1]||maze[xx][yy]=='#'||maze[xx][yy+1]=='#')
						continue;
					vis[xx][yy][1]=true;
					q.push(Node(xx,yy,cur.step+1,1));
				}
				else if(i==1||i==3)//flag=2
				{
					if(!check(xx,yy)||!check(xx+1,yy)||vis[xx][yy][2]||maze[xx][yy]=='#'||maze[xx+1][yy]=='#')
						continue;
					vis[xx][yy][2]=true;
					q.push(Node(xx,yy,cur.step+1,2));
				}
			}
		}
		else if(cur.flag==1)//若当前状态横着
		{
			for(int i=0;i<4;i++)
			{
				int xx=cur.x+b1[i][0];
				int yy=cur.y+b1[i][1];
				if(i==0||i==1)//flag=1
				{
					if(!check(xx,yy)||!check(xx,yy+1)||vis[xx][yy][1]||maze[xx][yy]=='#'||maze[xx][yy+1]=='#')
						continue;
					vis[xx][yy][1]=true;
					q.push(Node(xx,yy,cur.step+1,1));
				}
				else if(i==2||i==3)//flag=0
				{
					if(!check(xx,yy)||vis[xx][yy][0]||maze[xx][yy]=='#'||maze[xx][yy]=='E')
						continue;
					vis[xx][yy][0]=true;
					q.push(Node(xx,yy,cur.step+1,0));
				}
			}
		}
		else if(cur.flag==2)//若当前状态竖着
		{
			for(int i=0;i<4;i++)
			{
				int xx=cur.x+b2[i][0];
				int yy=cur.y+b2[i][1];
				if(i==0||i==1)//flag=2
				{
					if(!check(xx,yy)||!check(xx+1,yy)||vis[xx][yy][2]||maze[xx][yy]=='#'||maze[xx+1][yy]=='#')
						continue;
					vis[xx][yy][2]=true;
					q.push(Node(xx,yy,cur.step+1,2));
				}
				else if(i==2||i==3)//flag=0
				{
					if(!check(xx,yy)||vis[xx][yy][0]||maze[xx][yy]=='#'||maze[xx][yy]=='E')
						continue;
					vis[xx][yy][0]=true;
					q.push(Node(xx,yy,cur.step+1,0));
				}
			}
		}
	}
	return false;
}

int main()
{
	while(scanf("%d%d",&n,&m)!=EOF&&n+m)
	{
		for(int i=0;i<n;i++)
			scanf("%s",maze[i]);
		if(bfs())
			printf("%d\n",ans);
		else
			printf("Impossible\n");
	}
   


   
   
   
   
   
   

   
   

   
   
   
   
   
   
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值