您的位置:首页 > 其它

1、暴力破解与实用性原则

2018-03-08 21:41 399 查看

暴力破解与实用性原则:

    1)暴力破解的第一原则:实用性。
    2)枚举法。
    3)逆向解法。

真题一   年龄谜题

        美国数学家维纳(N.Wiener)智力早熟,11 岁就上了大学。 他曾在 1935-1936 年应邀来中国清华大学讲学。 一次,他参加某个重要会议,年轻的脸孔引人注目。 于是有人询问他的年龄,他回答说:“我年龄的立方是个 4 位数。我年龄的 4 次方是个6 位数。这 10 个数字正好包含了从 0 到 9 这 10 个数字,每个都恰好出现 1 次。”请你推算一下,他当时到底有多年轻。

解题思路:

    假设年龄是在1-50岁之间,暴力破解便是将1-50全部算出再筛选。
 1)计算1-50的立方以及4次方,剔除掉立方不是4位数的以及4次方不是6位数的结果。
       


       


        很明显,在这里就已经可以看出答案是18岁。暴力破解原则就是要实用、高效、快速。

 2)将年龄的立方以及4次方串起来,判断这10个数字是否正好包含了从0到9这10个数字,每个都恰好出现1次。
         思路:判断0-9是否都出现在串中。
        


完整代码:

public class Main{

public static void main(String[] args){

for (int i=1; i<50; i++) {
int a = i*i*i;
int b = a * i;
if((a+"").length() != 4 || (b+"").length() != 6)    //判断年龄的立方是否4位数以及4次方是否6位数
continue;
String s = "" + a + b;
System.out.println(i + ": " + s + " " + isAnswer(s));
}

}
//判断是否是答案
public static boolean isAnswer(String s){
for (int i=0; i<10; i++) {
if(s.indexOf(i+"") == -1) //0-9只要有一个不包含在s串中,直接返回false
return false;
}
return true;
}

}

结果:



真题二:古罗马数字(枚举法)

        古罗马帝国开创了辉煌的人类文明,但他们的数字表示法的确有些繁琐,尤其在示大数的时候,现在看起来简直不能忍受,所以在现代很少使用了。 之所以这样,不是因为发明表示法的人的智力的问题,而是因为一个宗教的原因,当时的宗教禁止在数字中出现 0 的概念! 罗马数字的表示主要依赖以下几个基本符号:
I --> 1
V --> 5
X --> 10
L --> 50
C --> 100
D --> 500
M --> 1000


这里,我们只介绍一下 1000 以内的数字的表示法。
单个符号重复多少次,就表示多少倍。最多重复 3 次。

比如: CCC 表示 300 XX 表示 20,但 150 并不用 LLL 表示,这个规则仅适用于 I  X C M。
如果相邻级别的大单位在右,小单位在左,表示大单位中扣除小单位。
比如: IX 表示 9 ,IV 表示 4 ,XL 表示 40  , 49 = XLIX
更多的示例参见下表,你找到规律了吗?
I = 1
II = 2
III = 3
IV = 4
V = 5
VI = 6
VII = 7
VIII = 8
IX = 9
X = 10
XI = 11
XII = 12
XIII = 13
XIV = 14
XV = 15
XVI = 16
XVII = 17
XVIII = 18
XIX = 19
XX = 20
XXI = 21
XXII = 22
XXIX = 29
XXX = 30
XXXIV = 34
XXXV = 35
XXXIX = 39
XL = 40
L = 50
LI = 51
LV = 55
LX = 60
LXV = 65
LXXX = 80
XC = 90
XCIII = 93
XCV = 95
XCVIII = 98
XCIX = 99
C = 100
CC = 200
CCC = 300
CD = 400
D = 500
DC = 600
DCC = 700
DCCC = 800
CM = 900
CMXCIX = 999

本题目的要求是:请编写程序,由用户输入若干个罗马数字串,程序输出对应的十进制表示。

输入格式是:第一行是整数 n,表示接下来有 n 个罗马数字(n<100)。 以后每行一个罗马数字。罗马数字大                              小 不 超 过 999。 要求程序输出 n 行,就是罗马数字对应的十进制数据。
 例如,用户输入:
    3
    LXXX
    XCIII
    DCCII
则程序应该输出:
   80
   93
   702

解题思路:

1、遍历罗马数字字符串的每一个字符,将每个字符所对应的十进制数相加起来。
    


2、因为存在着小单位在大单位左边这种情况,而且还不是所有的小单位放到大单位左边都成立。所以单单第一步是不够的,然而总结规律,这种特殊情况却少之又少:
    IV:4         IX:9
    XL:40       XC:90
    CD:400    CM:900

    因此,接下来就是直接枚举出这6种情况,对上述第一步所得出的sum进行补偿即可。

    


完整代码:

import java.util.Scanner;

public class Main{

public static void main(String[] args){
String[] romeNums = new String
;

Scanner s = new Scanner(System.in);
int n = s.nextInt();
for(int i=0; i<n; i++){
romeNums[i] = s.next();
}

for(int i=0; i<n; i++){
System.out.println(romeNumToDec(romeNums[i]));
}
}

public static int romeNumToDec(String romeNum){
int sum = 0;
for (int i=0; i<romeNum.length(); i++) {
char c = romeNum.charAt(i);
if(c == 'I')	sum += 1;
if(c == 'V')	sum += 5;
if(c == 'X')	sum += 10;
if(c == 'L')	sum += 50;
if(c == 'C')	sum += 100;
if(c == 'D')	sum += 500;
if(c == 'M')	sum += 1000;
}

//对sum进行补偿
if(romeNum.indexOf("IV") != -1)	sum -= 2;
if(romeNum.indexOf("IX") != -1)	sum -= 2;
if(romeNum.indexOf("XL") != -1)	sum -= 20;
if(romeNum.indexOf("XC") != -1)	sum -= 20;
if(romeNum.indexOf("CD") != -1)	sum -= 200;
if(romeNum.indexOf("CM") != -1)	sum -= 200;

return sum;
}
}

结果:



问题:如何保证输入的罗马数字是正确的呢?
解决:可以采用逆向解法。
1)将罗马数字转为十进制数字;
2)设计一个方法,将所得到的十进制反而再转化为罗马数字;
3)将转化来的罗马数字与之前的比较看是否一致。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: