JSOI2019冬令营,这题只会输出impossible骗10分,如今也算圆了当时的梦吧
读题发现:宽搜。因为要求最短时间,这和宽搜的长处很像,而且又是一个类似走迷宫的题。
标记当前状态:横坐标,纵坐标,目前已用的时间,余下的能量。
宽搜一定要记得判重! 开一个三维数组,定义为每一坐标(横加纵)和余下能量,如果已经出现过这种状态,那么就舍去。
Q:为什么不需要记录时间?A:因为能量不同,最后的总时间就可能不同,与当前的时间无关
搜索时分两步,首先看走路,然后看飞行。
Q:怎么表示飞的距离?A:乘法。
另:STL的queue可能慢一点,但是不需要手动开空间,而这题明显能够看出不同的状态极多,所以使用STL
具体见代码
#include<iostream>
#include<queue>
using namespace std;
int n,m,d;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
//const自动测算大小
struct node{
int x,y,e,t;
node(int _x,int _y,int _e,int _t):x(_x),y(_y),e(_e),t(_t){};
//这样可以直接变为结构体,免得先定义一个然后慢慢赋值
//具体原理其实我也不太懂,此处看的别人的代码
};
queue<node> q;
char se[107][107];
bool vis[107][107][107];
void bfs(){
while(!q.empty()){
node nw=q.front();
q.pop();//千万记得出队!!!不然卡死,还不知道为什么
for(int i=0;i<4;++i){//走路
int nx=nw.x+dx[i];
int ny=nw.y+dy[i];
if(nx<1||nx>n||ny<1||ny>m||se[nx][ny]=='L')continue;
if(vis[nx][ny][nw.e])continue;
vis[nx][ny][nw.e]=true;
if(nx==n&&ny==m){cout<<nw.t+1<<endl;return;}
//因为最后一步没有加进去,所以要+1
q.push(node(nx,ny,nw.e,nw.t+1));
}
for(int i=0;i<4;++i){
for(int j=2;j<=nw.e;++j){
int nx=nw.x+dx[i]*j;
int ny=nw.y+dy[i]*j;
if(nx<1||nx>n||ny<1||ny>m)break;
//因为用的能量越大,飞得越远,所以接下来用更多的能量肯定不行了,算是一个小剪枝
if(se[nx][ny]=='L')continue;
if(vis[nx][ny][nw.e-j])continue;
vis[nx][ny][nw.e-j]=true;
if(nx==n&&ny==m){cout<<nw.t+1<<endl;return;}
//因为最后一步没有加进去,所以要+1
q.push(node(nx,ny,nw.e-j,nw.t+1));
}
}
}
cout<<"impossible"<<endl;//记得输出不可能的情况
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>d;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
cin>>se[i][j];
q.push(node(1,1,d,0));
bfs();
return 0;
}