双端队列BFS
双端队列BFS其实就是dijkstra算法的特殊情况(边权只有0和1)
dijkstra的流程,就是先把源点放入优先队列,接下来重复以下操作(取出队列中距离源点最近的点,即优先队列的队头,用该点更新邻点的距离,再把更新后的距离放入队列)
每个点在出队的时候就说明从源点到该点的最短距离已经找到,因此要对这个点进行标记,后续计算时跳过该点
双端队列BFS也是一样,先把起点放入队列中,为了实现和优先队列相同的效果,当边权为0时,就把新点插入队头,是1时就插入队尾
电路维修
题意:旋转路线使左上角和右下角联通,求最小操作次数
//格点和格点的关系
int dx[]={-1,-1,1,1};
int dy[]={-1,1,1,-1};
//格点和格子的关系
int ix[]={-1,-1,0,0};
int iy[]={-1,0,0,-1};
char cs[5]="\\/\\/";
char g[N][N];
int dis[N][N];
bool vis[N][N];
int bfs(){
memset(vis,false,sizeof vis);
memset(dis,0x3f,sizeof dis);
dis[0][0]=0;
deque<PII> q;
q.push_front({0,0});
while(!q.empty()){
PII t=q.front();q.pop_front();
int x=t.first,y=t.second;
if(x==n&&y==m){
return dis[x][y];
}
vis[x][y]=true;
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||ny<0||nx>n||ny>m) continue;
if(vis[nx][ny]) continue;
int ga=x+ix[i],gb=y+iy[i];
int w=0;
if(g[ga][gb]!=cs[i]) w=1;
if(dis[nx][ny]>dis[x][y]+w){
dis[nx][ny]=dis[x][y]+w;
if(!w) q.push_front({nx,ny});
else q.push_back({nx,ny});
}
}
}
return -1;
}
int main(){
int t;cin>>t;
while(t--){
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>g[i];
}
//起点是(0,0),沿斜线走,横纵坐标同时变化1
//只能走到偶数点,奇数点走不到
if((n+m)&1){
cout<<"NO SOLUTION"<<endl;
}else{
cout<<bfs()<<endl;
}
}
}