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;
}
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;
}
题意:
给出一个迷宫,限定能往左走和往右走的次数分为为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;
}