【九度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 }
View Code

 

转载于:https://www.cnblogs.com/hadis-yuki/p/4389895.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值