【九度OJ】题目1482:玛雅人的密码 (bfs+hash)
题目1482:玛雅人的密码
时间限制:1 秒
内存限制:128 兆
特殊判题:否
提交:2076
解决:513
- 题目描述:
-
玛雅人有一种密码,如果字符串中出现连续的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年清华大学计算机研究生机试真题
- 分析:
- 关键是状态的转移,“每次只能移动相邻的两个数字”,由于最多13个数,则状态数不超过3^13 = 1394323
- 就根据这句话进行转移与计数。
- hash利用三进制计数- -(这个地方我开始又犯错了!)
-
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cmath> 6 #include<map> 7 #include<queue> 8 9 using namespace std; 10 11 char str[15]; 12 struct node 13 { 14 int a[15]; 15 int step,len; 16 }; 17 int cnt[3]; 18 queue<node> q; 19 bool vis[1594325]; //1594323 20 //int p[15] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192}; 21 node st; 22 23 bool mkhash(int *a,int len,int &num) 24 { 25 num = 0; 26 for(int i=0;i<len;i++) 27 { 28 // num += p[i]*a[i]; 29 num = num*3+a[i]; 30 } 31 return vis[num]; 32 } 33 34 bool check(int *a,int len) 35 { 36 for(int i=0;i<len;i++) 37 { 38 if(a[i]==2 && i+1<len && i+2<len && i+3<len && a[i+1]==0 && a[i+2]==1 && a[i+3]==2) 39 return true; 40 } 41 return false; 42 } 43 44 int solve() 45 { 46 while(!q.empty()) q.pop(); 47 memset(vis,0,sizeof(vis)); 48 49 st.step = 0; 50 q.push(st); 51 52 int num; 53 mkhash(st.a,st.len,num); 54 vis[num] = true; 55 56 node cur,next; 57 while(!q.empty()) 58 { 59 cur = q.front(); 60 q.pop(); 61 62 if(check(cur.a,cur.len)) 63 return cur.step; 64 65 66 for(int i=0;i<cur.len-1;i++) 67 { 68 memcpy(next.a,cur.a,sizeof(cur.a)); 69 int cal = 0; 70 swap(next.a[i],next.a[i+1]); 71 if(mkhash(next.a,cur.len,cal)) continue; 72 next.step = cur.step+1; 73 next.len = cur.len; 74 75 q.push(next); 76 vis[cal] = true; 77 } 78 } 79 return -1; 80 } 81 82 int main() 83 { 84 int len; 85 while(~scanf("%d",&len)) 86 { 87 scanf("%s",str); 88 memset(cnt,0,sizeof(cnt)); 89 for(int i=0;i<len;i++) 90 { 91 st.a[i] = str[i]-'0'; 92 cnt[st.a[i]]++; 93 } 94 st.len = len; 95 if(cnt[0]>=1 && cnt[1]>=1 && cnt[2]>=2) 96 { 97 printf("%d\n",solve()); 98 } 99 else printf("-1\n"); 100 } 101 return 0; 102 }