小学生题目:
小明五次输入四位数的手机密码均错误,但是每次输入的密码中都有两位数字正确,且输入的数字的位置都不正确。求小明正确的四位手机密码。
五次手机密码分别是:
6087 5173 1358 3825 2531
解:
使用排除法推导:
首先,在小明输入的数字中:12356780这八个数字中,选择两个数字,顺向推导。如果推导不顺利,最多需要推导8*8=64次。
…………省略不正确的推导过程。以下是正确的推导过程:
1、若正确的数字为5和3,
由1358 与2531 >>> 5与3在第1位与第4位;
由5173与3825 >>> 5与3在第2位与第3位;
互相矛盾——故正确的密码不包含3和5;
2、因为5与3是错误的数字,
由1358 >>> 8与1是正确的数字,
由2531 >>> 2与1是正确的数字,
由3825 >>> 8与2是正确的数字,
由5173 >>> 7和1是正确的数字,
故知,正确的密码包含的数字为 1,2,7,8。
3、正确的数字为 1,2,7,8
由6087 >>> 8不在第3位,7不在第4位,
由5173 >>> 1不在第2位,7不在第3位,
由1358 >>> 1不在第1位,8不在第4位,
由3825 >>> 8不在第2位,2不在第3位,
由2531 >>> 2不在第1位,1不在第4位,
综合:
1不在第2位 &&
1不在第1位 &&
1不在第4位 ——–故1只能是第3位
8不在第2位 &&
8不在第3位 &&
8不在第4位 ——–故8只能是第1位
7不在第4位 &&
7不在第3位 ——–故7可能在第1位和第2位
又由于第1位为8,故7只能在第2位
2不在第1位 &&
2不在第3位 ——–故2可能在第4位和第2位
又由于第2位为7,故2只能在第4位。
3、最后:
1只能是第3位
8只能是第1位
7只能在第2位
2只能在第4位
知正确的密码:8712
求得晕乎乎。至于为什么一开始就选中正确的数字进行推导,或许有更好的办法,但是我不知道。也许数学就是需要一个具有灵感的脑袋。
很明显,我灵感细胞缺乏,于是动手编程求解:
package test;
import java.util.ArrayList;
import java.util.Iterator;
public class NumsTest {
public static void main(String[] args) {
Work work = new Work();
work.working();
}
public static class Work{
private int[] a = {6,0,8,7};
private int[] b = {5,1,7,3};
private int[] c = {1,3,5,8};
private int[] d = {3,8,2,5};
private int[] e = {2,5,3,1};
//不存在数字4,9,遇到4,9时忽略
private ArrayList<int[]>lists;
public Work() {
lists = new ArrayList<int[]>();
lists.add(a);
lists.add(b);
lists.add(c);
lists.add(d);
lists.add(e);
}
public void working(){
for (int i = 0; i < 10000; i++) {
int num4 = i%10000/1000;
int num3 = i%1000/100;
int num2 = i%100/10;
int num1 = i%10/1;
boolean flag = false;
int[] nums = new int[]{num4,num3,num2,num1};
//不存在数字4,9,遇到4,9时忽略
for (int j = 0; j < nums.length; j++) {
int k = nums[j];
if (k==4||k==9) {
flag = true;
}
}
if (flag) continue;//跳到生成数字的下一次i+1循环
flag = jobing(nums);
if (flag) {
System.out.println("正确的密码:\n"+num4+""+num3+""+num2+""+num1);
}
}
}
/**
* @param num 遍历生成的所有4位数字组合密码。用于比对小明五次输入的密码。
* @return 当5次输入均符合条件:只有两个正确,且所有数字位置都不正确时返回true,表示得到了正确密码。
*/
private boolean jobing(int[] num){
int count=0;
for (Iterator<int[]> iterator = lists.iterator(); iterator.hasNext();) {
int[] is = (int[]) iterator.next();
boolean flag = doJob(num,is);
if (flag) {
count++;
}
}
if (count==lists.size()) {
return true;
}
return false;
}
/**
* @param ns 生成的表示密码所有4位组合的数组,范围为0000~9999
* @param ms 小明每次输入的密码数组
* @return true表示小明一次输入的密码和遍历生成的可能密码比对成功,符合要求
*/
private boolean doJob(int[] ns,int[] ms) {
/*
* 1、遍历求出包含正确数字的可能密码的数字串
*小明输入的密码每次都只有两个正确。
*当4位组合密码与小明输入的密码有两个数相同时,将可能数字串与其余四个输入比较
*
*ns=8721-8712---ms=3825,数字所有位置都不对
*第一位8--3,特点:第i位互不相同
*6655--3825
*/
int count=0;//用于记录数字组合中包含多少个小明输入的数字。包含2个即可能包含了正确密码
int coun=0;//用于记录有多少个数字位置不正确,所有第i数字不相等,即表示位置不正确。
for (int i = 0; i < ns.length; i++) {
int n = ns[i];
for (int k = 0; k < ms.length; k++) {
int m = ms[k];
if ( n==m ) {//存在相同数字,计数。
count++;
}
}
if (ns[i]!=ms[i]) {//当第i位互不相同,计数
coun++;
}
}
if (count==2 && coun==ns.length) {
//当只有两个数字正确,且所有数字位置都不正确时,一次比较成功,
//需比较5次(小明输入5次密码)
return true;
}
return false;
}
}
}
运行结果:
编程思路1: