【01BFS】# P4667 [BalticOI 2011] Switch the Lamp On 電路維修 (Day1)|普及+

本文涉及知識點

C++BFS算法

題目描述

Casper is designing an electronic circuit on a N × M N \times M N×M rectangular grid plate. There are N × M N \times M N×M square tiles that are aligned to the grid on the plate. Two (out of four) opposite corners of each tile are connected by a wire.

A power source is connected to the top left corner of the plate. A lamp is connected to the bottom right corner of the plate. The lamp is on only if there is a path of wires connecting power source to lamp. In order to switch the lamp on, any number of tiles can be turned by 90° (in both directions).
在這里插入圖片描述

在這里插入圖片描述

In the picture above the lamp is off. If any one of the tiles in the second column from the right is turned by 90° , power source and lamp get connected, and the lamp is on.

Write a program to find out the minimal number of tiles that have to be turned by 90° to switch the lamp on.

輸入格式

The first line of input contains two integer numbers N N N and M M M, the dimensions of the plate. In each of the following N N N lines there are M M M symbols – either \ or / – which indicate the direction of the wire connecting the opposite vertices of the corresponding tile.

輸出格式

There must be exactly one line of output. If it is possible to switch the lamp on, this line must contain only one integer number: the minimal number of tiles that have to be turned to switch on the lamp. If it is not possible, output the string: NO SOLUTION

輸入輸出樣例 #1

輸入 #1

3 5
\\/\\
\\///
/\\\\

輸出 #1

1

說明/提示

對于 40 % 40\% 40% 的數據, 1 ≤ N ≤ 4 1 \le N \le 4 1N4 1 ≤ M ≤ 5 1 \le M \le 5 1M5

對于所有數據, 1 ≤ N , M ≤ 500 1 \le N,M \le 500 1N,M500

BFS 雙向隊列

一,本題是點圖,不是單格圖。故:r ∈ \in [0,N],c ∈ \in [0,M]。
二,本題能否保證每個點都只訪問一次?vis記錄最少改變次數,改變次數變少,才需要重新處理當前點的后續。因為是01BFS,所以可以保證所有節點只訪問一次。
三,用雙向隊列,如果不改變入隊首,改變入隊尾。這樣優先處理不改變,可以提速。
時間復雜度:O(NM)
任意時刻:雙向隊列要么全部是x,要么前邊是x,后邊是x+1。
x入隊首,x+1入隊尾,扔保持這種狀態。故x處理完之前,不會處理x+1。

代碼

核心代碼

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>#include <bitset>
using namespace std;template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {in >> pr.first >> pr.second;return in;
}template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;return in;
}template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);return in;
}template<class T = int>
vector<T> Read() {int n;scanf("%d", &n);vector<T> ret(n);for(int i=0;i < n ;i++) {cin >> ret[i];}return ret;
}template<class T = int>
vector<T> Read(int n) {vector<T> ret(n);for (int i = 0; i < n; i++) {cin >> ret[i];}return ret;
}template<int N = 12 * 1'000'000>
class COutBuff
{
public:COutBuff() {m_p = puffer;}template<class T>void write(T x) {int num[28], sp = 0;if (x < 0)*m_p++ = '-', x = -x;if (!x)*m_p++ = 48;while (x)num[++sp] = x % 10, x /= 10;while (sp)*m_p++ = num[sp--] + 48;}inline void write(char ch){*m_p++ = ch;}inline void ToFile() {fwrite(puffer, 1, m_p - puffer, stdout);}
private:char  puffer[N], * m_p;
};template<int N = 12 * 1'000'000>
class CInBuff
{
public:inline CInBuff() {fread(buffer, 1, N, stdin);}inline int Read() {int x(0), f(0);while (!isdigit(*S))f |= (*S++ == '-');while (isdigit(*S))x = (x << 1) + (x << 3) + (*S++ ^ 48);return f ? -x : x;}
private:char buffer[N], * S = buffer;
};template<class TSave, class TRecord >
class CRangUpdateLineTree
{
protected:virtual void OnQuery(const TSave& save, const int& iSaveLeft, const int& iSaveRight) = 0;virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) = 0;virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight) = 0;virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;
};template<class TSave, class TRecord >
class CVectorRangeUpdateLineTree : public CRangUpdateLineTree<TSave, TRecord>
{
public:CVectorRangeUpdateLineTree(int iEleSize, TSave tDefault, TRecord tRecordNull) :m_iEleSize(iEleSize), m_save(iEleSize * 4, tDefault), m_record(iEleSize * 4, tRecordNull) {m_recordNull = tRecordNull;}void Update(int iLeftIndex, int iRightIndex, TRecord value){Update(1, 0, m_iEleSize - 1, iLeftIndex, iRightIndex, value);}void Query(int leftIndex, int rightIndex) {Query(1, 0, m_iEleSize - 1, leftIndex, rightIndex);}//void Init() {//	Init(1, 0, m_iEleSize - 1);//}TSave QueryAll() {return m_save[1];}void swap(CVectorRangeUpdateLineTree<TSave, TRecord>& other) {m_save.swap(other.m_save);m_record.swap(other.m_record);std::swap(m_recordNull, other.m_recordNull);assert(m_iEleSize == other.m_iEleSize);}
protected://void Init(int iNodeNO, int iSaveLeft, int iSaveRight)//{//	if (iSaveLeft == iSaveRight) {//		this->OnInit(m_save[iNodeNO], iSaveLeft);//		return;//	}//	const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;//	Init(iNodeNO * 2, iSaveLeft, mid);//	Init(iNodeNO * 2 + 1, mid + 1, iSaveRight);//	this->OnUpdateParent(m_save[iNodeNO], m_save[iNodeNO * 2], m_save[iNodeNO * 2 + 1], iSaveLeft, iSaveRight);//}void Query(int iNodeNO, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight) {if ((iSaveLeft >= iQueryLeft) && (iSaveRight <= iQueryRight)) {this->OnQuery(m_save[iNodeNO], iSaveLeft, iSaveRight);return;}if (iSaveLeft == iSaveRight) {//沒有子節點return;}Fresh(iNodeNO, iSaveLeft, iSaveRight);const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (mid >= iQueryLeft) {Query(iNodeNO * 2, iSaveLeft, mid, iQueryLeft, iQueryRight);}if (mid + 1 <= iQueryRight) {Query(iNodeNO * 2 + 1, mid + 1, iSaveRight, iQueryLeft, iQueryRight);}}void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value){if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight)){this->OnUpdate(m_save[iNode], iSaveLeft, iSaveRight, value);this->OnUpdateRecord(m_record[iNode], value);return;}if (iSaveLeft == iSaveRight) {return;//沒有子節點}Fresh(iNode, iSaveLeft, iSaveRight);const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;if (iMid >= iOpeLeft){Update(iNode * 2, iSaveLeft, iMid, iOpeLeft, iOpeRight, value);}if (iMid + 1 <= iOpeRight){Update(iNode * 2 + 1, iMid + 1, iSaveRight, iOpeLeft, iOpeRight, value);}// 如果有后代,至少兩個后代this->OnUpdateParent(m_save[iNode], m_save[iNode * 2], m_save[iNode * 2 + 1], iSaveLeft, iSaveRight);}void Fresh(int iNode, int iDataLeft, int iDataRight){if (m_recordNull == m_record[iNode]){return;}const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_record[iNode]);Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_record[iNode]);m_record[iNode] = m_recordNull;}vector<TSave> m_save;vector<TRecord> m_record;TRecord m_recordNull;const int m_iEleSize;
};class C01BFSDis
{
public:C01BFSDis(vector<vector<int>>& vNeiB0, vector<vector<int>>& vNeiB1, int s){m_vDis.assign(vNeiB0.size(), -1);std::deque<std::pair<int, int>> que;que.emplace_back(s, 0);while (que.size()){auto it = que.front();const int cur = it.first;const int dis = it.second;que.pop_front();if (-1 != m_vDis[cur]){continue;}m_vDis[cur] = it.second;for (const auto next : vNeiB0[cur]){if (-1 != m_vDis[next]){continue;}que.emplace_front(next, dis);}for (const auto next : vNeiB1[cur]){if (-1 != m_vDis[next]){continue;}que.emplace_back(next, dis + 1);}}}
public:vector<int> m_vDis;
};class Solution {
public:int Ans(vector<string>& mat) {const int R = mat.size();const int C = mat[0].size();auto Mask = [&](int r, int c) {return (C + 1) * r + c;};const int iMC = (R + 1) * (C + 1);vector<vector<int>> neiBo0(iMC), neiBo1(iMC);for (int r = 0; r < R; r++) {for (int c = 0; c < C; c++) {const int mask1 = Mask(r, c);const int mask2 = Mask(r + 1, c + 1);const int mask3 = Mask(r + 1, c);const int mask4 = Mask(r, c + 1);if ('\\' == mat[r][c]) {neiBo0[mask1].emplace_back(mask2);neiBo0[mask2].emplace_back(mask1);neiBo1[mask3].emplace_back(mask4);neiBo1[mask4].emplace_back(mask3);}else {neiBo0[mask3].emplace_back(mask4);neiBo0[mask4].emplace_back(mask3);neiBo1[mask1].emplace_back(mask2);neiBo1[mask2].emplace_back(mask1);}}}C01BFSDis bfs(neiBo0, neiBo1, 0);return bfs.m_vDis.back();}};int main() {
#ifdef _DEBUGfreopen("a.in", "r", stdin);
#endif // DEBUG	int R, C;cin >> R >> C;vector<string> mat(R);for (int r = 0; r < R; r++) {cin >> mat[r];}auto res = Solution().Ans(mat);if (res < 0) {cout << "NO SOLUTION";}else {cout << res;}	
#ifdef _DEBUG		/*printf("T=%d,", T);*/Out(mat, "mat=");
#endif // DEBUG	return 0;
}

單元測試

vector<string> mat;TEST_METHOD(TestMethod11){mat = { {"\\/"} };auto res = Solution().Ans(mat);AssertEx(-1, res);}TEST_METHOD(TestMethod12){mat = { {"\\/\\"} };auto res = Solution().Ans(mat);AssertEx(0, res);}TEST_METHOD(TestMethod13){mat = { {"///"} };auto res = Solution().Ans(mat);AssertEx(2, res);}TEST_METHOD(TestMethod14){mat = { "\\\\/\\\\","\\\\///","/\\\\\\\\" };auto res = Solution().Ans(mat);AssertEx(1, res);}

擴展閱讀

我想對大家說的話
工作中遇到的問題,可以按類別查閱鄙人的算法文章,請點擊《算法與數據匯總》。
學習算法:按章節學習《喜缺全書算法冊》,大量的題目和測試用例,打包下載。重視操作
有效學習:明確的目標 及時的反饋 拉伸區(難度合適) 專注
聞缺陷則喜(喜缺)是一個美好的愿望,早發現問題,早修改問題,給老板節約錢。
子墨子言之:事無終始,無務多業。也就是我們常說的專業的人做專業的事。
如果程序是一條龍,那算法就是他的是睛
失敗+反思=成功 成功+反思=成功

視頻課程

先學簡單的課程,請移步CSDN學院,聽白銀講師(也就是鄙人)的講解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成戰斗了,為老板分憂,請學習C#入職培訓、C++入職培訓等課程
https://edu.csdn.net/lecturer/6176

測試環境

操作系統:win7 開發環境: VS2019 C++17
或者 操作系統:win10 開發環境: VS2022 C++17
如無特殊說明,本算法用**C++**實現。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/75263.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75263.shtml
英文地址,請注明出處:http://en.pswp.cn/web/75263.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

參考平面跨分割情況下的信號回流

前言&#xff1a;弄清楚信號的回流路徑&#xff0c;是學習EMC和高速的第一步&#xff01; 如果我們不管信號的回流路徑&#xff0c;會造成什么后果&#xff1f;1、信號完整性問題&#xff0c;信號的回流路徑不連續會導致信號反射、衰減和失真。2、信號衰減和噪聲干擾&#xff…

almalinux 8 9 升級到指定版本

almalinux 8 update 指定版本 almalinux歷史版 所有版本almalinux最新版 所有版本vault歷史版 almalinux最新版 (https://repo.almalinux.org )地址后面增加不同名稱 echo "delete repos" rm -rf /etc/yum.repos.d/*echo "new almalinux repo" cat <&…

阿里云CDN應對DDoS攻擊策略

阿里云CDN遭遇DDoS攻擊時&#xff0c;可通過以下綜合措施進行應對&#xff0c;保障服務的穩定性和可用性&#xff1a; 1. 啟用阿里云DDoS防護服務 阿里云提供專業的DDoS防護服務&#xff0c;通過流量清洗中心過濾惡意流量&#xff0c;確保合法請求正常傳輸。該服務支持按需選…

CentOS Stream release 9安裝 MySQL(一)

在 CentOS Stream 上安裝 MySQL 的方法與傳統的 CentOS 類似&#xff0c;但由于 CentOS Stream 的軟件包更新策略不同&#xff0c;可能會遇到一些依賴問題。以下是詳細安裝步驟&#xff1a; 1. 添加 MySQL 官方 Yum 倉庫 sudo rpm -Uvh https://dev.mysql.com/get/mysql80-co…

數據結構 | 證明鏈表環結構是否存在

?個人主頁&#xff1a; 鏈表環結構 0.前言1.環形鏈表&#xff08;基礎&#xff09;2.環形鏈表Ⅱ&#xff08;中等&#xff09;3.證明相遇條件及結論3.1 問題1特殊情況證明3.2 問題1普適性證明 0.前言 在這篇博客中&#xff0c;我們將深入探討鏈表環結構的檢測方法&#xff1a;…

數字世界的免疫系統:惡意流量檢測如何守護網絡安全

在2023年全球網絡安全威脅報告中,某跨國電商平臺每秒攔截的惡意請求峰值達到217萬次,這個數字背后是無數黑客精心設計的自動化攻擊腳本。惡意流量如同數字世界的埃博拉病毒,正在以指數級速度進化,傳統安全防線頻頻失守。這場沒有硝煙的戰爭中,惡意流量檢測技術已成為守護網…

【JavaScript】十八、頁面加載事件和頁面滾動事件

文章目錄 1、頁面加載事件1.1 load1.2 DOMContentLoaded 2、頁面滾動事件2.1 語法2.2 獲取滾動位置 3、案例&#xff1a;頁面滾動顯示隱藏側邊欄 1、頁面加載事件 script標簽在html中的位置一般在</body>標簽上方&#xff0c;這是因為代碼從上往下執行&#xff0c;在htm…

Linux : 內核中的信號捕捉

目錄 一 前言 二 信號捕捉的方法 1.sigaction()?編輯 2. sigaction() 使用 三 可重入函數 四 volatile 關鍵字 一 前言 如果信號的處理動作是用戶自定義函數,在信號遞達時就調用這個函數,這稱為捕捉信號。在Linux: 進程信號初識-CSDN博客 這一篇中已經學習到了一種信號…

分布式id生成算法(雪花算法 VS 步長id生成)

分布式ID生成方案詳解:雪花算法 vs 步長ID 一、核心需求 全局唯一性:集群中絕不重復有序性:有利于數據庫索引性能高可用:每秒至少生成數萬ID低延遲:生成耗時<1ms二、雪花算法(Snowflake) 1. 數據結構(64位) 0 | 0000000000 0000000000 0000000000 0000000000 0 |…

函數式編程在 Java:Function、BiFunction、UnaryOperator 你真的會用?

大家好&#xff0c;我是你們的Java技術博主&#xff01;今天我們要深入探討Java函數式編程中的幾個核心接口&#xff1a;Function、BiFunction和UnaryOperator。很多同學雖然知道它們的存在&#xff0c;但真正用起來卻總是不得要領。這篇文章將帶你徹底掌握它們&#xff01;&am…

x265 編碼器中運動搜索 ME 方法對比實驗

介紹 x265 的運動搜索方法一共有 6 種方法,分別是 DIA、HEX、UMH、STAR、SEA、FULL。typedef enum {X265_DIA_SEARCH,X265_HEX_SEARCH,X265_UMH_SEARCH,X265_STAR_SEARCH,X265_SEA,X265_FULL_SEARCH } X265_ME_METHODS;GitHub

2025.4.8 dmy NOI模擬賽總結(轉化貢獻方式 dp, 交互(分段函數找斷點),SAM上計數)

文章目錄 時間安排題解T1.搬箱子(dp&#xff0c;轉化貢獻方式)T2.很多線。(分段函數找斷點)T3.很多串。(SAM&#xff0c; 計數) 時間安排 先寫了 T 3 T3 T3 60 p t s 60pts 60pts&#xff0c;然后剩下 2.5 h 2.5h 2.5h 沒有戰勝 T 1 T1 T1 40 p t s 40pts 40pts。 總得分…

ZYNQ筆記(四):AXI GPIO

版本&#xff1a;Vivado2020.2&#xff08;Vitis&#xff09; 任務&#xff1a;使用 AXI GPIO IP 核實現按鍵 KEY 控制 LED 亮滅&#xff08;兩個都在PL端&#xff09; 一、介紹 AXI GPIO (Advanced eXtensible Interface General Purpose Input/Output) 是 Xilinx 提供的一個可…

CSP認證準備第二天-第36/37次CCF認證

第37次CCF認證-第三題 主要是間接賦值比較難。 自己編寫的代碼如下&#xff0c;但是有問題&#xff0c;沒有解決間接賦值的問題&#xff0c;可以參考一下deepseek的回答。 #include <iostream> #include <bits/stdc.h> using namespace std; long long n,x; char …

Kotlin與HttpClient編寫視頻爬蟲

想用Apache HttpClient庫和Kotlin語言寫一個視頻爬蟲。首先&#xff0c;我需要確定用戶的具體需求。視頻爬蟲通常涉及發送HTTP請求&#xff0c;解析網頁內容&#xff0c;提取視頻鏈接&#xff0c;然后下載視頻。可能需要處理不同的網站結構&#xff0c;甚至可能需要處理動態加載…

FFMEPG常見命令查詢

基本參數 表格1&#xff1a;主要參數 參數說明-i設定輸入流-f設定輸出格式(format) 高于后綴名-ss開始時間-t時間長度codec編解碼 表格2&#xff1a;音頻參數 參數說明-aframes設置要輸出的音頻幀數-f音頻幀深度-b:a音頻碼率-ar設定采樣率-ac設定聲音的Channel數-acodec設定…

Java-對比兩組對象找出發生變化的字段工具-支持枚舉映射-支持時間-支持顯示對應字段中文描述-嵌套list等場景

實體字段比較器&#xff08;對比兩組對象找出發生變化的字段工具類開發&#xff09; 支持枚舉映射 支持時間 支持顯示對應字段中文描述 支持嵌套list等場景 下載地址&#xff1a; Java-對比兩組對象找出發生變化的字段工具-支持枚舉映射-支持時間-支持顯示對應字段中文描述-嵌…

15. git push

基本概述 git push 的作用是&#xff1a;把本地分支的提交推送到遠程倉庫。推送分支需要滿足快進規則&#xff08;Fast-Forward&#xff09;&#xff0c;即遠程分支的最新提交必須是本地分支的直接祖先&#xff0c;這個是通過哈希值值進行判斷的。 基本用法 1.完整格式 git…

訓練數據清洗(文本/音頻/視頻)

多數據格式的清洗方法 以下是針對多數據格式清洗方法的系統性總結&#xff0c;結合Python代碼示例&#xff1a; 一、數據清洗方法總覽&#xff08;表格對比&#xff09; 數據類型核心挑戰關鍵步驟常用Python工具文本非結構化噪聲去噪→分詞→標準化→向量化NLTK, SpaCy, Jie…

Python標準庫json完全指南:高效處理JSON數據

一、json庫概述 JSON(JavaScript Object Notation)是一種輕量級的數據交換格式&#xff0c;Python的json模塊提供了JSON數據的編碼和解碼功能。該模塊可以將Python對象轉換為JSON字符串&#xff08;序列化&#xff09;&#xff0c;也可以將JSON字符串轉換為Python對象&#xf…