1. 程式人生 > >算法提高 密碼鎖 (BFS)

算法提高 密碼鎖 (BFS)

自動打開 stream 其中 直接 思路 原來 格式 while int

問題描述
你獲得了一個據說是古代瑪雅人制作的箱子。你非常想打開箱子看看裏面有什麽東西,但是不幸的是,正如所有故事裏一樣,神秘的箱子出現的時候總是會掛著神秘的鎖。
這個鎖上面看起來有 N 個數字,它們排成一排,並且每個數字都在 0 到 2 之間。你發現你可以通過鎖上的機關來交換相鄰兩個數字的順序。比如,如果原來有 5 個數字 02120,在一次交換以後你就可以得到 20120,01220,02210 或者 02102。
根據你所搜集的情報,這個鎖在上面存在某連續四個數字是“2012”的時候會自動打開。現在,你需要計算一下,你至少需要進行多少次交換操作才能打開這把鎖?
輸入格式
輸入數據的第一行有一個正整數 N。(4 ≤ N ≤ 13) 輸入數據的第二行有 N 個數字 a1,a2, ..., aN ,其中 ai 表示這個鎖上面第 i 個數字的值,滿足 0 ≤ ai ≤ 2。這些數字之間沒有空格分隔。
輸出格式
你只需要輸出一個數字,即你至少需要的交換次數。如果無論如何都沒有希望打開這把鎖,輸出 -1。
樣例輸入
5
02120
樣例輸出
1
對樣例的解釋
把前兩個數字交換以後,鎖上的數字是 20120,其中存在連續四個數字2, 0, 1, 2,因此鎖會打開。

思路: 對於開鎖是當且僅當給定的的n個數字中出現2012,我們可以將這幾個數字當成字符串輸入 因為是求最小交換次數並且是每一次是一種新的狀態所以我們很容易想到用BFS

將每一次交換後的新的狀態和當前的交換次數加入隊列,每一次判斷是否達到開鎖的狀態;

註意: 因為每一次的交換可能會出現相同的狀態 所以我們在交換之後要註意 首先:如果即將交換的=兩個數字不同才進行交換,其次 如果交換後的狀態已經出現過了就不用入隊了

好了話不多說 直接上代碼吧

#include<iostream>
#include<algorithm>
#include<queue>
#include
<string> #include<set> using namespace std; typedef pair<string,int> P; queue<P>Q;set<string>S; int n; bool goal(string str)//判斷是否有達到開鎖的條件 { for(int i=0;i+3<str.size();i++) if(str[i]==2&&str[i+1]==0&&str[i+2]==1&&str[i+3]==2)
return true; return false; } void BFS() { while(!Q.empty()) { P q = Q.front(); Q.pop(); if(goal(q.first))//判斷有沒有達到可以開鎖的狀態 { cout<<q.second<<endl; return; } for(int i=0;i<q.first.size()-1;i++) { string str = q.first; if(str[i]!=str[i+1]) { swap(str[i],str[i+1]); if(goal(str)) { cout<<q.second+1<<endl; return; } if(S.count(str)!=1)//剪枝 對於已經出現過的狀態就不必再繼續 { //存入隊列 例如22010 如果在之後的的交換中 S.insert(str); //再一次出現22010 則不需要再對它進行交換 P p; //S 是set類型 用於記錄每一種情況有沒有出現過 p.first = str; //沒有則將其加入隊列 加入集合 p.second = q.second+1; Q.push(p); } } } } cout<<"-1"<<endl; } int main() { string str; P p; while(cin>>n>>str) { S.clear(); while(!Q.empty()) Q.pop(); p.first = str; p.second = 0; Q.push(p); BFS(); } return 0; }

算法提高 密碼鎖 (BFS)