洛谷P1379 八數碼難題【A-star】

P1379 八數碼難題

八數碼難題首先要進行有解性判定,避免無解情況下盲目搜索浪費時間。

有解性判定

P10454 奇數碼問題

題意簡述

在一個 n × n n \times n n×n 的網格中進行,其中 n n n 為奇數, 1 1 1 個空格和 [ 1 , n 2 ? 1 ] [1,n^2 - 1] [1,n2?1] n 2 ? 1 n^2 - 1 n2?1 個數不重不漏地分布在網格中。空格可與上下左右的數字交換位置。現給定兩個奇數碼游戲的局面,判定是否存在一種移動空格的方式使得互相可達。

實際上,八數碼問題就是一個 n = 3 n = 3 n=3 的奇數碼游戲。

思路

將網格圖轉為長為 n 2 ? 1 n^2 - 1 n2?1 的一維序列,例如:

5 2 8
1 3 _
4 6 7

可記為 5 , 2 , 8 , 1 , 3 , 4 , 6 , 7 5 ,2,8,1,3,4,6,7 5,2,8,1,3,4,6,7 ,忽略空格。可以發現:若左右移動空格,該序列不變;若上下移動空格,例如:

5 2 _
1 3 8
4 6 7

序列變為 5 , 2 , 1 , 3 , 8 , 4 , 6 , 7 5,2,1,3,8,4,6,7 5,2,1,3,8,4,6,7 ,相當于把 8 8 8 往前移動了 n ? 1 = 2 n - 1 = 2 n?1=2 位,有兩個數字到了 8 8 8 的后面,那么這兩個數字中,原來與 8 8 8 形成逆序對的變成了非逆序對,原來與 8 8 8 形成非逆序對的變成了逆序對。

進一步思考:

1.若在位置發生變動的數中原有奇數個逆序對,由于 n ? 1 n - 1 n?1 是偶數,那么原來也有奇數個非逆序對,因此交換后逆序對的個數仍為奇數;

2.若在位置發生變動的數中原有偶數個逆序對,由于 n ? 1 n - 1 n?1 是偶數,那么原來也有偶數個非逆序對,因此交換后逆序對的個數仍為偶數。

綜上所述,無論怎么交換,逆序對個數的奇偶性不變,因此可以比較初狀態和末狀態的逆序對(用樹狀數組統計)奇偶性是否相同,方可判定是否有解。

代碼實現

注意 0 0 0 不參與統計,忘了這一點會 WA。

#include <bits/stdc++.h>using namespace std;int n;int lowbit(int p){return p & (-p);}void insert(int p,int x,vector <int>& c){for(;p <= n;p += lowbit(p))c[p] += x;
} int query(int p,vector <int>& c){int sum = 0;for(;p;p -= lowbit(p)) sum += c[p];return sum;
}int main(){ios::sync_with_stdio(0);cin.tie(0);while(cin >> n){n = n * n; vector <int> c(n + 1,0);int x,ans1,ans2,cnt1,cnt2;cnt1 = cnt2 = ans1 = ans2 = 0;for(int i = 1;i <= n;i++){cin >> x;if(!x) continue;cnt1++;insert(x,1,c);ans1 += cnt1 - query(x,c);}for(int i = 0;i <= n;i++) c[i] = 0;for(int i = 1;i <= n;i++){cin >> x;if(!x) continue;cnt2++; insert(x,1,c);ans2 += cnt2 - query(x,c);}	if(ans1 % 2){if(ans2 % 2) cout << "TAK" << endl;else cout << "NIE" << endl;}else{if(ans2 % 2) cout << "NIE" << endl;else cout << "TAK" << endl;}}return 0;
}

A-star

其實本題不需要可行性判定,但學一下也無妨。

設計估價函數 h ( s t a t e ) h(state) h(state) 表示當前狀態所有數字與其目標位置的曼哈頓距離和,即:
h ( s t a t e ) = ∑ i = 1 8 ∣ x i ? x t a r g e t ∣ + ∣ y i ? y t a r g e t ∣ h(state) = \sum_{i = 1}^{8} \left | x_i - x_{target} \right | + \left | y_i - y_{target} \right | h(state)=i=18?xi??xtarget?+yi??ytarget?
顯然實際操作數 g ( s t a t e ) ≥ h ( s t a t e ) g(state) \ge h(state) g(state)h(state) ,因為 h h h 表示每個數字去目標點都走最短路,而實際至少得走這么遠, h h h 函數可采納且較接近真實值(相比之下“錯位數”,即不在目標位置的數字個數,這一估價函數雖可采納但大多數時候遠小于真實值,求解效率低),最終入隊的總代價即為 f = g + h f = g + h f=g+h

代碼實現

#include <bits/stdc++.h>using namespace std;const string TARGET = "123804765";
const int dx[] = {0,0,-1,1};
const int dy[] = {-1,1,0,0};struct Node{string state;int g,h,f;Node(string s,int _g,int _h) :state(s),g(_g),h(_h),f(_g + _h) {}//重載運算符bool operator < (const Node& other) const {return f > other.f;} 
};//預處理target狀態坐標
void initTargetPos(unordered_map <char,int>& pos_map){for(int i = 0;i < 9;i++){char c = TARGET[i];if(c != '0') pos_map[c] = i;}
} //函數求曼哈頓距離和 
int mahattan(const string& state,const unordered_map <char,int>& pos_map){int distance = 0;for(int i = 0;i < 9;i++){char c = state[i];if(c == '0') continue;int target_pos = pos_map.at(c);//當前數字坐標 int cur_x = i % 3;int cur_y = i / 3;//目標位置坐標 int tar_x = target_pos % 3;int tar_y = target_pos / 3;distance += abs(cur_x - tar_x) + abs(cur_y - tar_y);}return distance;
}int A_star(string start){if(start == TARGET) return 0;//預處理目標位置 unordered_map <char,int> pos_map;initTargetPos(pos_map);priority_queue <Node> open_list;unordered_map <string,int> min_cost;int start_h = mahattan(start,pos_map);open_list.push(Node(start,0,start_h));min_cost[start] = 0;while(!open_list.empty()){Node cur = open_list.top();open_list.pop();string state = cur.state;if(state == TARGET) return cur.g;//非最優路徑則跳過if(min_cost[state] < cur.g) continue;//找出0的位置 int pos = state.find('0');int x = pos % 3;int y = pos / 3;for(int i = 0;i < 4;i++){int tx = x + dx[i];int ty = y + dy[i];//越界 if(tx < 0 || tx >= 3 || ty < 0 || ty >= 3) continue;//0的新坐標 int new_pos = tx + ty * 3;string new_state = state;swap(new_state[pos],new_state[new_pos]);int new_g = cur.g + 1;//未曾入隊或有更優解 if(min_cost.find(new_state) == min_cost.end() || new_g < min_cost[new_state]){min_cost[new_state] = new_g;int new_h = mahattan(new_state,pos_map);open_list.push(Node(new_state,new_g,new_h));} }}
}int main(){ios::sync_with_stdio(0);cin.tie(0);string start;cin >> start;cout << A_star(start) << endl;return 0;
}

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

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

相關文章

MySQL Buffer Pool 深度解析:從架構設計到性能優化(附詳細結構圖解)

在 MySQL 數據庫的世界里&#xff0c;有一個決定性能上限的"神秘倉庫"——Buffer Pool。它就像超市的貨架&#xff0c;把最常用的商品&#xff08;數據&#xff09;放在最方便拿取的地方&#xff0c;避免每次都要去倉庫&#xff08;磁盤&#xff09;取貨。今天我們就…

使用numpy的快速傅里葉變換的一些問題

離散傅里葉變換&#xff08;DFT&#xff09;的頻率&#xff08;或波數&#xff09;確實主要由采樣點數和物理步長決定。 最高波數和最小波長的乘積是1。單位長度內波的周期數。 &#xff08;注意角波數是 k 2 π λ k \frac{2 \pi}{\lambda} kλ2π?&#xff09; 使用numpy…

DVWA靶場通關筆記-CSRF(High級別)

目錄 一、CSRF Token 二、代碼審計&#xff08;High級別&#xff09; 1、滲透準備 2、源碼分析 三、滲透實戰 1、滲透準備 2、修改URL重放失敗 3、burpsuite嘗試重放失敗 4、安裝CSRF Token Tracker 5、安裝logger插件 6、配置CSRF Token Tracker 7、bp再次重放報文…

Redis實戰:數據安全與性能保障

數據安全 持久化策略 RDB持久化&#xff1a;通過創建快照將內存中的數據寫入到磁盤上的RDB文件中。可以在配置文件中設置save參數來指定在多少秒內有多少次寫操作時觸發快照保存。例如&#xff0c;save 900 1表示900秒內至少有1次寫操作時保存快照。 AOF持久化&#xff1a;將每…

人臉活體識別3:C/C++實現實時眨眼、張嘴、點頭、搖頭檢測

> 當AI能識破照片與真人的區別,我們才真正跨入生物識別安全時代 --- ### 一、活體檢測:數字世界的守門人 **傳統人臉識別的致命缺陷**: - 高清照片欺騙成功率 > 85% - 視頻回放攻擊成本 < $50 - 3D面具破解率高達72% **我們的解決方案**: ```mermaid graph …

【Linux】AlmaLinux 無法使用root用戶登錄cockpit控制臺問題解決

在虛擬機安裝AlmaLinux 9.6&#xff0c;安裝過程中需要允許使用root用戶和SSH協議登錄服務器。但是&#xff0c;在使用root用戶登錄cockpit管理后臺時&#xff0c;系統提示“權限被拒絕”。 經過查詢資料&#xff0c;可以通過下面的方法來解決此問題。 編輯 /etc/cockpit/disa…

【Java面試】講講HashMap的常用方法,以及底層實現?

1. 底層數據結構 數組鏈表紅黑樹&#xff08;JDK 1.8&#xff09;&#xff1a; 數組&#xff08;Node[] table&#xff09;存儲桶&#xff08;bucket&#xff09;&#xff0c;每個桶是鏈表或紅黑樹的頭節點。鏈表解決哈希沖突&#xff0c;當鏈表長度 ≥ 8 且數組容量 ≥ 64 時…

ToT:思維樹:借助大語言模型進行審慎的問題求解

摘要 語言模型正日益被部署于廣泛任務中的通用問題求解&#xff0c;但在推理階段仍受限于 token 級、從左到右的決策過程。這意味著在需要探索、戰略前瞻&#xff0c;或初始決策起關鍵作用的任務中&#xff0c;語言模型可能表現不佳。為克服這些挑戰&#xff0c;我們提出了一種…

Web3 + RWA 餐飲數字化解決方案白皮書(試點版)

一、背景&#xff1a;從“用戶”到“共創股東”&#xff0c;重構本地生活新邏輯 ? 項目愿景&#xff1a; “用一頓飯&#xff0c;鏈接一個社群&#xff1b;用一次消費&#xff0c;綁定一份權益”。 傳統商業以“交易”為中心&#xff0c;未來商業則以“關系 價值流轉”為核…

MCU的模擬輸入ADC引腳如何實現采樣時間與阻抗匹配

在MCU的模擬輸入ADC引腳中&#xff0c;實現采樣時間與阻抗匹配是關鍵的設計環節&#xff0c;直接影響采樣精度。以下是分步說明&#xff1a; 【】理解信號源阻抗與采樣時間的關系 ? 信號源阻抗&#xff08;Rs&#xff09;&#xff1a;外部信號源的輸出阻抗&#xff08;如傳感器…

等價矩陣 線性代數

所謂等價矩陣&#xff0c;就是說其秩相同的矩陣。 例題 A和B等價就是求A和B的秩&#xff0c;其實就是要求B的秩了&#xff0c;因為目標已經告訴你了A和B的秩是一樣的。那么怎么求B的秩呢&#xff1f;我們現在只有一種方法求其秩&#xff0c;就是通過把其經過初等變換之后符合標…

30.設計模式的優缺點

原文地址:設計模式的優缺點 更多內容請關注&#xff1a;智想天開 一、設計模式的優點 1. 提高代碼復用性與可維護性 復用性&#xff1a; 設計模式提供的是抽象的解決方案&#xff0c;可以在多個項目中重復應用&#xff0c;避免重復造輪子。例如&#xff0c;工廠模式封裝了對象…

Python 爬蟲實戰 | 國家醫保

一、國家醫保 1、目標網站 網址&#xff1a;https://fuwu.nhsa.gov.cn/nationalHallSt/#/search/drug-directory目標數據&#xff1a;獲取藥品信息 2、網站特點 服務端返回加密數據&#xff0c;客戶端發送請求攜帶的載荷也是加密的 3、定位解密入口 可以通過關鍵字encDa…

OpenCV CUDA模塊設備層----計算向量的平方根函數sqrt

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 OpenCV 的 CUDA 設備函數&#xff08;device function&#xff09;&#xff0c;用于在 GPU 上計算一個 uchar4 類型向量的平方根&#xff0c;并返…

鴻蒙應用開發:HTTP訪問網絡

一、HTTP概述 在許多場景下&#xff0c;我們的應用需要從服務端獲取數據&#xff0c;例如&#xff0c;天氣應用需要從天氣服務器獲取天氣數據。新聞應用需要從新聞服務器獲取最新的新聞咨詢&#xff0c;通過HTTP數據請求&#xff0c;我們可以將互聯網上的信息展示在應用中&…

【Elasticsearch】refresh與提交

在Elasticsearch中&#xff0c;Translog日志的提交確實涉及到與刷新&#xff08;Refresh&#xff09;時寫入Lucene段的數據進行合并&#xff0c;并最終寫入磁盤。以下是詳細的步驟和解釋&#xff1a; 一、Translog日志的提交過程 1. 刷新&#xff08;Refresh&#xff09;操作 …

服務器異常宕機或重啟導致 RabbitMQ 啟動失敗問題分析與解決方案

服務器異常宕機或重啟導致 RabbitMQ 啟動失敗問題分析與解決方案 一、深度故障診斷與解決方案1. 權限配置不當故障2. 端口占用故障3. 數據目錄殘留故障 二、故障類型對比與診斷矩陣三、完整恢復流程&#xff08;10步法&#xff09;四、風險規避與最佳實踐&#x1f6e1;? 數據保…

車載以太網都有什么協議?

目錄 一、物理層協議(Physical Layer)二、數據鏈路層協議(Data Link Layer)三、網絡層協議(Network Layer)四、傳輸層協議(Transport Layer)五、應用層協議(Application Layer)六、車載網絡融合協議七、標準化組織八、協議分層總結表九、趨勢與未來協議車載以太網涉及…

設計模式之外觀模式:簡化復雜系統的優雅之道

設計模式之外觀模式&#xff1a;簡化復雜系統的優雅之道 今天我們來深入探討設計模式中的外觀模式&#xff08;Facade Pattern&#xff09;。想象一下&#xff0c;你走進一家高檔餐廳&#xff0c;只需要告訴服務員"我要一份A套餐"&#xff0c;而不需要關心廚房里廚師…

《Python 架構之美:三大設計模式實戰指南》

《Python 架構之美:三大設計模式實戰指南》 在軟件世界中,設計模式是經驗的結晶,它為開發者提供了解決重復問題的通用模板。尤其在 Python 這種靈活而強大的語言中,設計模式并非“死規矩”,而更像“編程哲學”,為我們解構復雜系統、提升代碼可維護性提供了寶貴思路。 本…