电路板(旋转元件)题解复盘
模块:0-1 BFS / 图论建模
目标:将电路板转化为图模型,用 0-1 BFS 求最少旋转次数
基本信息
| 项目 | 内容 |
|---|---|
| 题目编号、来源 | 未知(电路板 / 旋转元件) |
| 训练层级 | B 图论建模 |
| 知识版块 | 0-1 BFS、建图、最短路 |
解题前・关键信号识别
| 维度 | 分析 |
|---|---|
| 目标、约束、底层结构 | 目标 :从左上角到右下角连通电源,最少旋转元件次数;约束 :N,M ≤ 500;底层结构:每个元件连接一对对角点,旋转即切换对角线。 |
| 数据规模 | N×M ≤ 250000,点数为 (N+1)×(M+1) ≤ 251001,边数约为 4×N×M,0-1 BFS O(V+E) 可行。 |
| 候选算法和依据 | 0-1 BFS;依据:每次操作代价为 0(无需旋转)或 1(旋转一次),等价于求边权为 0/1 的最短路。 |
| 复杂度预判 | 时间复杂度 O((N+1)(M+1)),空间复杂度 O((N+1)(M+1))。 |
解题后・外化复盘
| 维度 | 内容 |
|---|---|
| 核心思路 | 把每个格点(电路交点)作为图节点,共有 (N+1)×(M+1) 个节点。每个元件占据一个方格,连接其两组对角顶点之一。根据当前字符决定哪些对角线已连接,未连接的对角线需要旋转一次。建图后求左上角 (0,0) 到右下角 (n,m) 的最短路。 |
| 建图方法 | 对于格子 (i,j),四个角:a = (i,j),b = (i,j+1),c = (i+1,j),d = (i+1,j+1)。若字符为 \,默认连接 a-d,需旋转才能连接 b-c,故加边 a-d 和 d-a 权 0,b-c 和 c-b 权 1。若字符为 /,默认连接 b-c,需旋转才能连接 a-d,故加边相反。 |
| 为什么用 0-1 BFS | 边权只有 0 和 1,普通 BFS 不适用,Dijkstra 可行但 O(E log V) 较慢,0-1 BFS 用双端队列实现 O(V+E) 更优。 |
| 错因回溯 | 1. 节点编号计算错误,应为 id(x,y) = x*(m+1) + y;2. 建图时方向搞反,把 / 和 \ 的边权弄颠倒;3. 忘记处理边界,导致越界;4. 用 BFS 而非 0-1 BFS,因为边权为 0 时普通队列会失效。 |
| 边界和易错点 | 1. 点数 = (n+1)*(m+1),索引从 0 开始;2. 字符 \ 在 C++ 中需要转义为 '\\';3. 0-1 BFS 中边权为 0 时 push_front,为 1 时 push_back;4. 无法到达时输出 NO SOLUTION(注意空格和大小写)。 |
| 下次看到什么信号,我应该想到这个方法 | 看到「旋转 90° 连接不同的对角线 + 求最少操作次数」,想到图建模 + 0-1 BFS。 |
AC 完整代码(按你提供的代码)
cpp
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <set>
#include <vector>
#include <deque>
using namespace std;
const int INF=0x3f3f3f;
int n,m;
int id(int x,int y){
return x*(m+1)+y;
}
struct Edge{
int to,w;
};
vector<vector<Edge>> g;
vector<int> dist;
int dx[4] = {-1,-1,1,1};
int dy[4] = {-1,1,-1,1};
void addedge(int u,int v,int w){
g[u].push_back({v,w});
}
void bfs(int s){
deque<int>dq;
fill(dist.begin(),dist.end(),INF);
dist[s]=0;
dq.push_front(s);
while(!dq.empty()){
int u=dq.front();
dq.pop_front();
for(auto e:g[u]){
int v=e.to;
int w=e.w;
if(dist[v]>dist[u]+w){
dist[v]=dist[u]+w;
if(w==0){
dq.push_front(v);
}else{
dq.push_back(v);
}
}
}
}
}
int main(){
cin>>n>>m;
int cnt=(n+1)*(m+1);
g.resize(cnt);
dist.resize(cnt);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
char x;
cin>>x;
int a=id(i,j);
int b=id(i,j+1);
int c=id(i+1,j);
int d=id(i+1,j+1);
if(x=='\\'){
addedge(a,d,0);
addedge(d,a,0);
addedge(c,b,1);
addedge(b,c,1);
}else{
addedge(a,d,1);
addedge(d,a,1);
addedge(c,b,0);
addedge(b,c,0);
}
}
}
bfs(id(0,0));
int ans=dist[id(n,m)];
if(ans==INF) cout<<"NO SOLUTION";
else cout<<ans;
return 0;
}