P4667 [BalticOI 2011] Switch the Lamp On复盘

电路板(旋转元件)题解复盘

模块: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-dd-a 权 0,b-cc-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;
}
相关推荐
别动我齐刘海1 小时前
机器人运动控制学习2——基础进阶
c++·人工智能·神经网络·学习·目标检测·机器学习·机器人
傻啦嘿哟2 小时前
英雄联盟皮肤爬虫:爬取全皮肤价格与特效,做比价工具
java·c++·爬虫
码匠许师傅3 小时前
【C++ 面试真题】24. 聊聊 C++ 的时间日期处理
java·c++·面试
闻道且行之3 小时前
图片处理助手|泊松融合原理 + C++ 工程实现,seamlessClone 三模式一次讲透
数据库·c++·人工智能·opencv
莫浅子4 小时前
day01-USB架构与枚举
c++·单片机·嵌入式驱动
小欣加油4 小时前
leetcode3069 将元素分配到两个数组中I
数据结构·c++·算法·leetcode·职场和发展
不会代码的小猴5 小时前
7. JSON
开发语言·c++·笔记·qt·算法·json
沫璃染墨5 小时前
《Qt从零入门系列(六):信号与槽进阶——从多种连接方式到Lambda表达式》
开发语言·c++·qt·代码规范·设计规范·qt5
小小龙学IT6 小时前
ZeroMQ(libzmq)开源消息库深度解析:brokerless 时代的轻量消息内核
c++·开源
Benny_Tang7 小时前
题解:P10230 [COCI 2023/2024 #4] Lepeze
c++·算法