题目1482:玛雅人的密码
时间限制:1 秒
内存限制:128 兆
特殊判题:否
提交:1351
解决:368
-
题目描述:
-
玛雅人有一种密码,如果字符串中出现连续的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
-
来源:
- 2012年清华大学计算机研究生机试真题
-
- 思路:MAP+预判+BFS+剪枝
- c++代码:
-
//1482 玛雅人的密码 //宽搜+剪枝 #include<cstdio> #include<string> #include<queue> #include<map> #include<iostream> using namespace std; struct Node { string str; int t; Node(string s, int l) { str = s; t = l; } }; bool match(string str)//匹配判断 { int size=str.size(); for(int i=0;i<size-3;i++) { if(str[i]=='2' && str[i+1]=='0' && str[i+2]=='1' && str[i+3]=='2') return true; } return false; } //指定子字符串数目 int count(string s,string t) { int res = 0, pos = s.find(t,0); while(pos != string::npos) { res++; pos = s.find(t,pos+1); } return res; } int main(void) { string str; int length; map<string,int> mp; while(cin >> length >> str) { bool found = false; //提前判断,很关键 string c0("0"),c1("1"),c2("2"); if(count(str,c2)<2 || count(str,c1)<1 || count(str,c0)<1) { printf("-1\n"); continue; } int size = 0; mp.clear(); mp[str]=size++; if(match(str))//不需要移动 { printf("0\n"); continue; } queue<Node> qn; qn.push(Node(str,0)); Node nd("",0); while(!qn.empty()) { nd = qn.front(); qn.pop(); if(match(nd.str))//已找到 { found = true; break; } for(int i=0; i<length-1; ++i) { string cal = nd.str; swap(cal[i],cal[i+1]);//交换 //检查是否已经查找过 if(mp.find(cal)==mp.end()) { qn.push(Node(cal,nd.t+1)); mp[nd.str] = size++;//置为已访问 } } } if(found) { printf("%d\n",nd.t); } else { printf("-1\n"); } } return 0; }