逻辑题:两个自然数a,b

已知两个自然数a,b,满足a>=2,b>=2。现有甲乙两人,甲知道a+b的值,乙知道a*b的值。
(1)甲对乙说:我不知道这两个数,但是我知道你也不知道;
(2)乙対甲说:我本来不知道,但是我现在知道了;
(3)甲说:我也知道了。
要求:
1,求出一对这样的值;
2,这样的值有多对,用代码求出多组这样的值。

思考:
试想,如果甲知道的数字是4,那么甲,乙均知道这两个数:a=b=2;
如果甲知道的数字是5,那么甲知道这两个数,分别是2,3,第(1)句话不成立;
如果甲知道的数字是6,那么甲不知道这两个数,因为这两个数可能是2,4或3,3,但是如果是2,4,那么乙知道的数是8,乙知道这两个数是2,4;如果是3,3,那么乙知道的数字是9,乙也知道,这两个数均是3,故第(1)句不成立;
如果甲知道的数字是7,那么甲不知道这两个数,可能是2,5或3,4;若是2,5,乙知道的是10,那么乙也知道这两个数,第(1)句不成立;
如果甲知道的数字是8,那么甲不知道这两个数,可能是2,6或3,5或4,4;若是3,5,第(1)句不成立;
如果甲知道的数字是9,那么甲不知道这两个数,可能是2,7或3,6或4,5;若是2,7,第(1)句不成立;
如果甲知道的数字是10,那么可能是2,8或3,7或4,6或5,5;若是3,7或5,5,第(1)句不成立;
如果甲知道的数字是11,那么可能是2,9或3,8或4,7或5,6;若是2,9,乙知道的是18,则乙无法确定这两个数是2,9还是3,6,即乙无法确定;若是3,8,乙知道的数是24,乙无法确定是3,8还是4,6还是2,12,即乙无法确定;若是4,7,则乙知道的数是28,乙无法确定是2,14还是4,7,即已无法确定;若是5,6,则乙知道的数是30,已无法确定是2,15还是3,10还是5,6,即乙无法确定。故第(1)句满足;
然后看第(2)句,乙在听到甲的话后,乙就知道了,甲的话直接排除了上面这些可能,乙由此知道了这两个值,乙如果拿的是18,则在乙看来,可能是2,9或3,6,若是2,9,则甲确实不知道,甲也可以推出乙不知道,若是3,6,甲手里是9,则甲没办法知道乙不知道,故3,6不符合,所以,乙此时可以知道是2,9,即2,9也满足第(2)句;乙如果拿的是24,对于乙来说可能是2,12或3,8或4,6,若是2,12,甲拿的是14,14可能是2,12或3,11或4,10或5,9或6,8或7,7,如果是3,11或7,7,则甲没办法确定乙一定不知道,不满足第(1)句;若是3,8,则甲手里是11,满足前两句;若是4,6,则甲手里是10,由上面分析可知,甲如果拿的是10,则不能断定乙不知道这两个数,故此时,乙确定不是4,6;故弱乙手里是24,则乙可以推断出是3,8,即3,8也满足第二句;乙如果拿的是28,则乙不确定是2,14还是4,7,若是2,14,则甲手里是16,16=3+13的时候甲不确定乙不知道,故不是2,14,若是4,7,甲手里是11,故此时乙也可以推断出是4,7,即4,7也满足第二句;若是30,则乙不确定是2,15还是3,10还是5,6,若是2,15,则甲是17,满足,若是3,10,则甲是13,13=2+11不满足第一句,若是5,6,甲是11,也满足,故乙在听到甲的话后任然无法确实是2,15还是5,6,所以乙手里不可能是30;
由上分析,可能的数值组合有
(2,9),甲:11;乙:18
(3,8),甲:11;乙:24
(4,7),甲:11;乙:28
然后看第三句,甲听了乙的话后,甲也知道了,所以甲手里不能是11,因为此时甲任然无法确定是上面三个中的哪一个,故上面没有正解。

由上归纳总结:
假设X=a+b,Y=ab
条件A:已知常数X,任取m,n满足m+n=X,至少另外一对(m‘,n’)满足m‘>=2,n’>=2, m‘n’ = mn, m!=m’, n!=n’;换种表述,任取m,n满足m+n=X,m,n不全为质数(例如3,5,乙如果知道两数之积是15,就能知道这两个数),且m,n中如果有一个是质数,则另一个数不能是该质数的平方(例如3,9,乙如果知道两数之积是27,就能知道这两数);这两种表述,对应的是两种不同的算法,分别对应下面代码中situation11和situation12两个方法。
条件B:已知常数Y,所有满足m
n=Y的(m,n)数对不止一对,但是这些数对中,P=m+n,满足条件A的常量P只有一个;
条件C:已知常量X,所有满足m+n=X的数对(m,n),取Y=m+n满足条件B的数对(m,n)只有一组。
同时满足上面三个条件的(m,n)即为最终待求数对。

先贴结果:100以内的这样数组有三组:
(4,13),(4,61),(16,73)
200以内这样的数有9组,1000以内这样的数有36组。。。

代码:

public class SpecialPair {

public static void main(String[] args) {
    List<Integer> origin = new ArrayList<>();
    long start = System.currentTimeMillis();
    for (int i = 4; i < 1000; i++) {
        origin.add(i);
    }
    List<Integer> firstResult = firstFilter(origin);
    System.out.println("firstResult = " + firstResult);
    LinkedHashMap<Integer, List<SortedPair>> secondResult = secondFilter(firstResult);
    System.out.println("secondResult = " + getHashMapString(secondResult));
    List<SortedPair> thirdResult = thirdFilter(secondResult);
    System.out.println("thirdResult = " + thirdResult);

    System.out.println("search " + thirdResult.size() + " results in range [" + origin.get(0)
            + ", " + origin.get(origin.size() - 1) + "] cost " + (System.currentTimeMillis() - start) + " ms!");
}

private static <K, V> String getHashMapString(HashMap<K, V> map) {
    if (map.size() < 1) {
        return "{}";
    }
    StringBuilder sb = new StringBuilder().append("{");
    for (K k : map.keySet()) {
        sb.append("\n" + k + ": " + map.get(k));
    }
    sb.append("\n}");
    return sb.toString();
}

/**
 * 甲对乙说:我不知道,但是我知道你也不知道
 *
 * @param origin
 * @return
 */
private static List<Integer> firstFilter(List<Integer> origin) {
    List<Integer> result = new ArrayList<>();
    for (int i : origin) {
        if (situation12(i)) {
            result.add(i);
        }
    }
    return result;
}

/**
 * 是否满足条件1
 *
 * @param num
 * @return
 */
private static boolean situation11(int num) {
    if (num < 4) {
        return false;
    }
    int mid = num / 2;

    for (int i = 2; i <= mid; i++) {
        int pro = i * (num - i);
        int found = 0;
        int n = (int) Math.sqrt(pro);
        for (int j = 2; j <= n; j++) {
            if (pro % j == 0) {
                found++;
            }

            if (found >= 2) {
                break;
            }
        }
        if (found == 1) {
            return false;
        }
    }
    return true;
}

private static boolean situation12(int num) {
    if (num < 4) {
        return false;
    }
    int mid = num / 2;
    for (int i = 2; i <= mid; i++) {
        if (isPrimePair(i, num - i) || isPrimeSquare(i, num - i)) {
            return false;
        }
    }
    return true;
}

/**
 * 乙対甲说:我本来不知道,现在我知道了
 *
 * @param origin
 * @return
 */
private static LinkedHashMap<Integer, List<SortedPair>> secondFilter(List<Integer> origin) {
    LinkedHashMap<Integer, List<SortedPair>> result = new LinkedHashMap<>();
    for (int sum : origin) {
        List<SortedPair> pairs = situation2(sum);
        if (pairs != null && pairs.size() > 0) {
            result.put(sum, pairs);
        }
    }
    return result;
}

private static List<SortedPair> situation2(int num) {
    if (num < 4) {
        return null;
    }
    int mid = num / 2;
    List<SortedPair> pairs = new ArrayList<>();
    for (int i = 2; i <= mid; i++) {
        int pro = i * (num - i);
        SortedPair sortedPair = checkPro(pro);
        if (sortedPair != null) {
            pairs.add(sortedPair);
        }
    }
    return pairs;
}

/**
 * 甲说:我也知道了
 *
 * @param pairs
 * @return
 */
private static List<SortedPair> thirdFilter(LinkedHashMap<Integer, List<SortedPair>> pairs) {
    List<SortedPair> result = new ArrayList<>();
    for (int key : pairs.keySet()) {
        if (pairs.get(key).size() == 1) {
            result.add(pairs.get(key).get(0));
        }
    }
    return result;
}


private static boolean isPrimePair(int a, int b) {
    return isPrimeNum(a) && isPrimeNum(b);
}

private static boolean isPrimeSquare(int a, int b) {
    return isPrimeNum(a) && (b == a * a)
            || isPrimeNum(b) && (b * b == a);
}

private static boolean isPrimeNum(int num) {
    if (num < 2) {
        return false;
    }
    int n = (int) Math.sqrt(num);
    for (int i = 2; i <= n; i++) {
        if (num % i == 0) {
            return false;
        }
    }
    return true;
}


private static SortedPair checkPro(int num) {
    if (num < 4) {
        return null;
    }
    int n = (int) Math.sqrt(num);
    SortedPair sortedPair = null;
    for (int i = 2; i <= n; i++) {
        if (num % i == 0) {
            int j = num / i;
            if (situation12(i + j)) {
                if (sortedPair == null) {
                    sortedPair = new SortedPair(i, j);
                } else if (!sortedPair.equals(new SortedPair(i, j))) {
                    return null;
                }
            }
        }
    }
    return sortedPair;
}


static class SortedPair {
    int first;
    int second;

    public SortedPair(int first, int second) {
        this.first = first <= second ? first : second;
        this.second = first <= second ? second : first;
    }

    @Override
    public boolean equals(@Nullable Object obj) {
        if (!(obj instanceof SortedPair)) {
            return false;
        }
        SortedPair pair = (SortedPair) obj;
        if (this == pair) {
            return true;
        }
        return first == pair.first && second == pair.second;
    }

    public int getSum() {
        return first + second;
    }

    public int getPro() {
        return first * second;
    }

    @Override
    public String toString() {
        return "SortedPair{" +
                "first=" + first +
                ", second=" + second +
                ", sum=" + getSum() +
                ", pro=" + getPro() +
                '}';
    }
}

}

补充:
经某大神提示,哥德巴赫猜想在这里是可以用的。
哥德巴赫猜想:任一大于2的偶数都可写成两个质数之和。
结合上面条件A的另外一种表述,可以知道甲知道的两数之和一定不是偶数,这样在代码层面只需要遍历奇数,第一次过滤效率可以提高一倍。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值