题解报告:hdu 1015 Safecracker

Problem Description
=== Op tech briefing, 2002/11/02 06:42 CST ===  "The item is locked in a Klein safe behind a painting in the second-floor library. Klein safes are extremely rare; most of them, along with Klein and his factory, were destroyed in World War II. Fortunately old Brumbaugh from research knew Klein's secrets and wrote them down before he died. A Klein safe has two distinguishing features: a combination lock that uses letters instead of numbers, and an engraved quotation on the door. A Klein quotation always contains between five and twelve distinct uppercase letters, usually at the beginning of sentences, and mentions one or more numbers. Five of the uppercase letters form the combination that opens the safe. By combining the digits from all the numbers in the appropriate way you get a numeric target. (The details of constructing the target number are classified.) To find the combination you must select five letters v, w, x, y, and z that satisfy the following equation, where each letter is replaced by its ordinal position in the alphabet (A=1, B=2, ..., Z=26). The combination is then vwxyz. If there is more than one solution then the combination is the one that is lexicographically greatest, i.e., the one that would appear last in a dictionary." 
v - w^2 + x^3 - y^4 + z^5 = target 
"For example, given target 1 and letter set ABCDEFGHIJKL, one possible solution is FIECB, since 6 - 9^2 + 5^3 - 3^4 + 2^5 = 1. There are actually several solutions in this case, and the combination turns out to be LKEBA. Klein thought it was safe to encode the combination within the engraving, because it could take months of effort to try all the possibilities even if you knew the secret. But of course computers didn't exist then." 
=== Op tech directive, computer division, 2002/11/02 12:30 CST === 
"Develop a program to find Klein combinations in preparation for field deployment. Use standard test methodology as per departmental regulations. Input consists of one or more lines containing a positive integer target less than twelve million, a space, then at least five and at most twelve distinct uppercase letters. The last line will contain a target of zero and the letters END; this signals the end of the input. For each line output the Klein combination, break ties with lexicographic order, or 'no solution' if there is no correct combination. Use the exact format shown below."
译文: === Op科技简报,2002/11/02 06:42 CST === 
“该物品被锁在二楼图书馆一幅油画后面的克莱恩保险柜中,克莱因保险柜非常罕见,其中大部分与克莱恩及其工厂一起在二战时被摧毁。幸运的是,老布鲁博从研究中知道克莱因在他去世前写下他们的秘密,一个克莱因保险箱有两个显着特点:一个使用字母而不是数字的组合锁,以及一扇刻在门上的刻字引号Klein引用总是包含5到12个不同的大写字母,通常在句子的开头,并提到一个或多个数字。大写字母组成打开的安全相结合,通过数字从所有的数字中,你得到一个数字目标适当的方式合并。(建设目标的细节五号码被分类。)要找到组合,您必须选择满足以下等式的五个字母v,w,x,y和z,其中每个字母由其在字母表中的顺序位置替换(A = 1,B = 2,...,Z = 26)。这个组合就是vwxyz。如果有多个解决方案,那么这个组合就是词典上最大的那个,也就是最后出现在字典中的那个。“v - w ^ 2 + x ^ 3 - y ^ 4 + z ^ 5 =目标”例如,给定目标1和字母集ABCDEFGHIJKL,一个可能的解决方案是FIECB,因为6 - 9 ^ 2 + 5 ^ 3 - 3 ^ 4 + 2 ^ 5 = 1。在这种情况下实际上有几个解决方案, Klein认为在雕刻中对组合进行编码是安全的,因为即使你知道秘密也需要数月的努力来尝试所有的可能性,但当然电脑当时并不存在。”
=== Op技术指令,计算机部门,2002/11/02 12:30 CST ===
“制定一个程序,以发现Klein组合,为野外部署做准备,按照部门规定使用标准测试方法,输入包含一个或多个行,其中包含一个不超过1200万的正整数,一个空格,然后至少5个,最多 十二个不同的大写字母,最后一行将包含零和字母END的目标;这表示输入结束,对于每行输出的克莱因组合,断开与字典顺序的关系,或者如果没有 正确的组合,请使用下面显示的确切格式。“
Sample Input
1 ABCDEFGHIJKL
11700519 ZAYEXIWOVU
3072997 SOUGHT
1234567 THEQUICKFROG
0 END
Sample Output
LKEBA
YOXUZ
GHOST
no solution
解题思路:题目的意思就是给你一个字母字符串,从中找出5个字母组成最大字典序,并且满足那个表达式,深搜即可。注意慎用pow函数会有误差,此处用了一个函数单独判断是否满足表达式,当表达式满足后还要判断当前的字符串t是否大于字符串g,是的话就 拷贝覆盖字符串g,g成为最大的字典序字符串。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 char s[15],t[6],g[6];//s是输入的一串,t是临时保存字母,g是存放最终的5个字母(最大字典序)
 4 int target,len,a[26];//a数组来保存字母对应的数字
 5 bool vis[26];
 6 bool isobj(int v,int w,int x,int y,int z,int tar){
 7     if(v - w*w + x*x*x - y*y*y*y + z*z*z*z*z == tar) return true;
 8     else return false;
 9 }
10 void dfs(int k)
11 {
12     if(k==5){//边界条件
13         if(isobj(a[t[0]-'A'],a[t[1]-'A'],a[t[2]-'A'],a[t[3]-'A'],a[t[4]-'A'],target) && strcmp(t,g)>0)
14             strcpy(g,t);//与目标相等时,还要按照字典序较大的输出
15         return;//回溯,返回上一层
16     }
17     for(int i=0;i<len;i++){//遍历字符串
18         if(!vis[s[i]-'A']){//如果当前字母没有访问
19             t[k]=s[i];//先存到t数组中
20             vis[s[i]-'A']=true;//并标记为暂时的访问过
21             dfs(k+1);//从每个当前位置进行深搜
22             vis[s[i]-'A']=false;//不满足条件的把原来标记的记为未访问过(回溯)
23         }
24     }
25 }
26 int main()
27 {
28     for(int i=0;i<26;i++)a[i]=i+1;//对26个字母进行编号赋值
29     while(cin>>target>>s && (target||strcmp(s,"END"))){
30         memset(vis,false,sizeof(vis));//初始化为假值,表示都未访问过
31         memset(g,'\0',sizeof(g));//全部赋为'\0',便于拷贝和整体输出
32         memset(t,'\0',sizeof(t));
33         len=strlen(s);//目标字符串的长度
34         dfs(0);//从第0个目标字符开始深搜
35         if(strlen(g)==0)cout<<"no solution"<<endl;//如果g的长度仍是0,则没有解
36         else cout<<g<<endl;//否则输出g字符串
37     }
38     return 0;
39 }

以上是深搜目标字符串,找出其中最大字典序字符串,但其实我们只需要将目标字符串中的字母进行降序排列,然后深搜找到第一个满足表达式的字符串,即为最大字典序字符串。AC解法二代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 char s[15],t[6];//s是输入的一串,t是临时保存字母
 4 int target,len,a[26];//a数组来保存字母对应的数字
 5 bool flag,vis[26];//flag标记是否找到
 6 bool isobj(int v,int w,int x,int y,int z,int tar){
 7     if(v - w*w + x*x*x - y*y*y*y + z*z*z*z*z == tar) return true;
 8     else return false;
 9 }
10 void dfs(int k)
11 {
12     if(k==5){//边界条件
13         if(isobj(a[t[0]-'A'],a[t[1]-'A'],a[t[2]-'A'],a[t[3]-'A'],a[t[4]-'A'],target) && !flag){
14             flag=true;cout<<t<<endl;//找到第一个字符串直接输出即可,此时就是最大字典序
15         }
16         return;//直接返回
17     }
18     for(int i=len-1;i>=0;--i){//从后往前遍历字符串
19         if(!vis[s[i]-'A']){//如果当前字母没有访问
20             t[k]=s[i];//先存到t数组中
21             vis[s[i]-'A']=true;//并标记为暂时的访问过
22             dfs(k+1);//从每个当前位置进行深搜
23             vis[s[i]-'A']=false;//不满足条件的把原来标记的记为未访问过(回溯)
24         }
25     }
26 }
27 int main()
28 {
29     for(int i=0;i<26;i++)a[i]=i+1;//对26个字母进行编号赋值
30     while(cin>>target>>s && (target||strcmp(s,"END"))){
31         memset(vis,false,sizeof(vis));//初始化为假值,表示都未访问过
32         memset(t,'\0',sizeof(t));
33         len=strlen(s);//目标字符串的长度
34         flag=false;sort(s,s+len);//排序
35         dfs(0);//从第0个目标字符开始深搜
36         if(!flag)cout<<"no solution"<<endl;//找不到
37     }
38     return 0;
39 }

猜你喜欢

转载自www.cnblogs.com/acgoto/p/9029841.html