-
题目描述:
-
玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串,(2=<N<=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。
-
输入:
-
输入包含多组测试数据,每组测试数据由两行组成。
第一行为一个整数N,代表字符串的长度(2<=N<=13)。
第二行为一个仅由0、1、2组成的,长度为N的字符串。
-
输出:
-
对于每组测试数据,若可以解出密码,输出最少的移位次数;否则输出-1。
-
样例输入:
-
5 02120
-
样例输出:
-
1
这个题第一眼看上去好像不难,但做起来却不知道如何下手。一开始思路往动态规划上靠,可是状态转移方程真实难以想明白。
想了很久,实在是想不明白,只好翻了翻别人的题解,这才知道原来是用广度优先搜索来做。
一道题找对方法真的很重要。
那么搜索时状态即为字符串的排列情况,利用map来记录该状态是否被访问过。检查每一个状态是否符合要求,一旦符合,就是最小的次数。
代码如下1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 8 using namespace std; 9 int cnt[3]; 10 typedef pair<string, int> Node; 11 map <string, int> mapping; 12 13 string str; 14 queue <Node> que; 15 16 bool isOk(string s) { 17 int len = s.size(); 18 for (int i = 0; i <= len-4; i++) { 19 if (s[i] == '2' && s[i + 1] == '0' && s[i + 2] == '1' && s[i + 3] == '2') { 20 return true; 21 } 22 } 23 return false; 24 } 25 26 int main() { 27 int n; 28 while (scanf("%d", &n) != EOF) { 29 cin >> str; 30 int len = str.size(); 31 memset(cnt, 0, sizeof(cnt)); 32 for (int i = 0; i < len; i++) { 33 cnt[str[i] - '0']++; 34 } 35 if (cnt[0] < 1 || cnt[1] < 1 || cnt[2] < 2) { 36 puts("-1"); 37 continue; 38 } 39 while (!que.empty()) { 40 que.pop(); 41 } 42 mapping.clear(); 43 mapping[str] = 1; 44 que.push(Node(str, 0)); 45 int ans = -1; 46 while (!que.empty()) { 47 Node p = que.front(); que.pop(); 48 string t = p.first; 49 int step = p.second; 50 if (isOk(t)) { 51 ans = step; 52 break; 53 } 54 for (int i = 0; i+1 < len; i++) { 55 string tmp = t; 56 swap(tmp[i], tmp[i + 1]); 57 if (mapping.find(tmp) == mapping.end()) { 58 mapping[tmp] = 1; 59 que.push(Node(tmp, step + 1)); 60 } 61 } 62 63 } 64 printf("%d\n", ans); 65 66 } 67 return 0; 68 }
这种题题面很简单,做起来代码其实也很简单,但就是想不到该用什么样的方法,但一旦找对方法,问题就迎刃而解了