洛谷 P1126 搬运重物
1.题目链接
https://www.luogu.com.cn/problem/P1126
2.解题思路
解题思路 这种题一看就是BFS (边权为1的最短路 或者 说 BFS根据时间一步一步走的,当走到那个点的时候一定就是最短路 但这个题目小的细节特别多QAQ )
具体如下
-
给的 是方格的颜色
-
我们的方格是从1开始计数的
-
给定的起点 或者说我们走的点 如果为 ( x , y ) (x,y) (x,y)的话 那么方格对应 的坐标就是 ( x + 1 , y + 1 ) (x+1,y+1) (x+1,y+1) 举个例子 也就是说 如果起点是 ( 7 , 2 ) (7,2) (7,2) 的话 那么对应的方格是第八行的第三个方格
-
因此 x坐标我们可以看作从0开始到n y坐标我们可以看作从0开始到m 但是0和上界限我们是不可以走的 因为机器人有体积
-
然后就是关于 障碍物 障碍物给的是方格的颜色 比如方格坐标是 ( 3 , 4 ) (3,4) (3,4) 那么 (2,3),(2,4),(3,3),(3,4)都是不能走的 那么我们给定以一个坐标
-
对应的 如果我们走的点 给定是 ( x , y ) (x,y) (x,y) 那么 (x+1,y+1) (x+1,y),(x,y+1),(x,y)都是不能走的 这个我们可以这么想 每一个方格的右下角做坐标对应的是我们走的点 比如方格是第八行第三列 那么左上角的坐标对应的是(7,2) 右下角对应 (8,3) 也就是方格的坐标 那么我们对于给定的坐标的话 我们就假设他是 方格的右下角 看看这个方格是不是黑色的具体可以看图
对于给定的(x,y)我们只需要四个红点不是黑色就行 因为只有这四个点和他有关 (注意 这里 右下角坐标对应我们的方格 )
//答案应该走的路
// 4个坐标分别为 x,y,方向,时间
7 2 2 0
7 2 1 1
7 1 1 2
7 1 0 3
4 1 0 4
1 1 0 5
1 1 3 6
1 4 3 7
1 5 3 8
1 5 2 9
2 5 2 10
2 5 3 11
2 7 3 12
3.代码
ACcoding
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long int LL;
typedef pair<int,pair<int,int> > PII;
typedef pair<int,int> PII1;
int n,m;
const int N=60;
int a[N][N];
//检查周围是否吐了黑色
bool check_direction(int x,int y)
{
int dx[4]={1,1,0,0};
int dy[4]={1,0,0,1};
for(int i=0;i<=3;i++)
{
if(a[x+dx[i]][y+dy[i]]==1)
{
return 0;
}
}
return 1;
}
// d[N][N][4] 用来在某个位置 面向某个方向 的时间
LL d[N][N][4];
LL ans=0;
//检查是否已经到了终点
bool check(PII end)
{
int x=end.first;
int y=end.second.first;
for(int i=0;i<4;i++)
{
if(d[x][y][i]!=-1)
return 1;
}
return 0;
}
//完成方向字符串到实数的转换
int exchange(char s)
{
if(s=='N')
return 0;
if(s=='W')
return 1;
if(s=='S')
return 2;
if(s=='E')
return 3;
}
//根据方向 返回我们怎么走 比如 向N方向走 就返回 dx=-1 dy=0;
PII1 exchange_direction(int x)
{
PII1 temp;
if(x==0)
{
temp.first=-1;
temp.second=0;
return temp;
}
if(x==1)
{
temp.first=0;
temp.second=-1;
return temp;
}
if(x==2)
{
temp.first=1;
temp.second=0;
return temp;
}
temp.first=0;
temp.second=1;
return temp;
}
LL bfs()
{
memset(d,-1,sizeof(d));
PII begin;
cin>>begin.first>>begin.second.first;
PII end;
cin>>end.first>>end.second.first;
char s;
cin>>s;
queue<PII > q;
begin.second.second=exchange(s);
q.push(begin);
int direction=exchange(s);
d[begin.first][begin.second.first][direction]=0;
while(q.size())
{
auto temp=q.front();
q.pop();
// x代表当前的横坐标 y代表当前的纵坐标 direction_temp代表当前的方向
int x=temp.first;
int y=temp.second.first;
int direction_temp=temp.second.second;
// cout<<x<<" "<<y<<" "<<direction_temp<<" "<<d[x][y][direction_temp]<<endl;
int left=(direction_temp+1+4)%4;
int right=(direction_temp-1+4)%4;
if(d[x][y][left]==-1)
{d[x][y][left]=d[x][y][direction_temp]+1;
q.push({x,{y,left}});
}
if(d[x][y][right]==-1)
{
d[x][y][right]=d[x][y][direction_temp]+1;
q.push({x,{y,right}});
}
PII1 direction_temp1=exchange_direction(direction_temp);
for(int i=1;i<=3;i++)
{
int dx=direction_temp1.first;
int dy=direction_temp1.second;
if(d[x+dx*i][y+dy*i][direction_temp]==-1&&x+dx*i>=1&&y+dy*i>=1&&x+dx*i<n&&y+dy*i<m&&check_direction(x+dx*i,y+dy*i)==1)
{
d[x+dx*i][y+dy*i][direction_temp]=d[x][y][direction_temp]+1;
q.push({x+dx*i,{y+dy*i,direction_temp}});
}
if(x+dx*i<1||x+dx*i>=n||y+dy*i<1||y+dy*i>=m||check_direction(x+dx*i,y+dy*i)==0)
break;
}
if(check(end)==1)
{
LL ans=1e9;
for(int i=0;i<=3;i++)
{
int x=end.first;
int y=end.second.first;
if(d[x][y][i]!=-1)
ans=min(ans,d[x][y][i]);
}
return ans;
}
}
return -1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
}
}
cout<<bfs();
return 0;
}