CF1749E双端队列BFS
GalwayGirl · · 题解
看没有题解,就想着来交一发题解。
Sloution
看到这道题,首先可以想到两种方法,第一种是模拟出怪物的行动路线用仙人掌隔断,但复杂度令我不敢尝试,第二种就是bfs仙人掌的种植路线,也就是我接下来会讲的正解。
首先,仙人掌四联通格子不能同时种,所以bfs的方向只能是斜着的四个方向,然后题目要求种植的仙人掌要最少,所以肯定想到这条隔断上方的仙人掌路线要尽可能经过原本的仙人掌,所以就可以将到仙人掌格子的边权设为
建议练习板子题。 P4667 [BalticOI 2011 Day1]Switch the Lamp On
最后贴上代码
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
const int dx[]={0,0,1,-1,1,1,-1,-1};
const int dy[]={1,-1,0,0,1,-1,1,-1};
const int N=2e5+100;
struct xzh{
int x,y;
};
vector<int>pre[N],dis[N];
string a[N];
deque<xzh>q;
bool check(int x,int y){
if(x<0||x>=n||y<0||y>=m)return false;
for(int i=0;i<4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]=='#')return false;
}
return true;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++)dis[i].clear(),pre[i].clear();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
dis[i].push_back(2e9);
pre[i].push_back(0);
}
}
for(int i=0;i<n;i++){
if(a[i][0]=='#')q.push_front({i,0}),dis[i][0]=0;
else if(check(i,0))q.push_back({i,0}),dis[i][0]=1;
}
while(!q.empty()){
int x=q.front().x,y=q.front().y;
q.pop_front();
for(int i=4;i<8;i++){
int xx=x+dx[i],yy=y+dy[i];
if(!check(xx,yy))continue;
int s=(a[xx][yy]=='.');
if(dis[xx][yy]>dis[x][y]+s){
dis[xx][yy]=dis[x][y]+s;
pre[xx][yy]=i;
if(s)q.push_back({xx,yy});
else q.push_front({xx,yy});
}
}
}
int min_=2e9,minn;
for(int i=0;i<n;i++){
if(dis[i][m-1]<min_){
min_=dis[i][m-1];minn=i;
}
}
if(min_==2e9){
printf("NO\n");
continue;
}
printf("YES\n");
int x=minn,y=m-1;
while(1){
a[x][y]='#';
if(!pre[x][y])break;
int ls=pre[x][y];
x-=dx[ls];y-=dy[ls];
}
for(int i=0;i<n;i++){
cout<<a[i];
printf("\n");
}
}
return 0;
}