• 一道难题


    题意

    你取定0到15中的一个整数,我会询问七个问题来确定这个数,你用“是”或者“否”回答我的问题,你允许撒一次慌(但也可以不撒谎),询问完毕,我会返回你猜的数

    题解

    看到这个题,很多人会直接想到二分法,但是这道题的回答会有一次撒谎,所以一旦在二分过程中被撒谎,整个二分方向都会出错。我又想到分块后二分,但还是有一点问题。最后我求助于二进制数才把这个问题解决了。
    因为0到15可以用四位二进制数表示。所以首先,用四个问题确定每个二进制位,这可以用按位与解决:
    question 1: x & 1 = 1?
    question 2: x & 2 = 2?
    question 3: x & 4 = 4?
    question 4: x & 8 = 8?
    根据四个回答,可以大致确定猜的数的二进制数每一位,当然因为回答可能有撒谎,这个数可能会有某一个二进制位与猜的数不同。但我们还有三个问题。
    我们记根据前四个回答确定的数为y,用第五个问题判断末三个二进制位有无问题:
    question 5: x & 7 = (y & 7)?

    1. 如果回答为是,说明最后三个数一定是没问题的,如果之前在后三位撒谎,那么此时一定要回答否(因为最多撒谎一次),那么剩下两个问题连续提问第一个二进制位,
      question 6: x & 8 = 8?
      如果回答为是,之前也肯定没撒谎,y则是答案
      如果回答为否,说明在这一位上的两次询问一定存在撒谎,但我们不知道是哪一次撒谎,于是再次询问
      question 7: x & 8 = 8?
      这次一定可以得到真实回答,由此可以判断x
    2. 如果回答为否,说明最后三位有一个二进制位有问题或者都没问题但问题5得到了撒谎的回答。但这一次矛盾可以确定已经撒过谎了,所以之后的询问一定能有放心的回答,为缩小范围,我们询问最后两位:
      question 6: x & 3 = (y & 3)?
      2.1. 如果回答为是,说明最后两位没问题,再询问倒数第三位:
      question 7: x & 4 = (y & 4)?
      这一次回答一定是真实的,可以因此判断x
      2.2 如果回答为否,说明最后两位一定有一位撒谎了,再询问最后一位:
      question 6: x & 1 = (y & 1)?
      如果回答为是,将y的倒数第二位取反,如果回答为否,将y的最后一位取反即可

    代码

    /*************************************************************************
    	> File Name: 1.cpp
    	> Author: Knowledge_llz
    	> Mail: 925538513@qq.com 
    	> Blog: https://www.cnblogs.com/Knowledge-Pig/
    	> Created Time: 2020/10/20 12:19:55
     ************************************************************************/
    #include<iostream>
    #define For(i,a,b) for(register int i=(a);i<=(b);++i)
    using namespace std;
    int cnt=0,ans,x=0;
    void output(){
    	printf("I guess it!
    ");
    	system("pause");
    	printf("The selected number is %d. Right?
    ",x);
    	system("pause");
    }
    int main()
    {
    	printf("This is a game program.
    ");
    //	printf("你取定0到15中的一个整数,我会询问七个问题来确定这个数,你用“是”或者“否”回答我的问题,你允许撒一次慌(但也可以不撒谎),询问完毕,我会返回你猜的数
    ");
    	system("pause");
    	printf("You choose an integer from 0 to 15.I will ask 7 questions to determine the number.You should use "Yes" or "No" to answer my question and you're allowed to lie to me but only once (you can choose to not to lie at all).After all questions, the program will return the selected number.
    ");
    	system("pause");
    	printf("To simplify the input.
     If you want to tell me "Yes",please input 1
     If you want to tell me "No",please input 0
    ");
    	system("pause");
    	printf("Hint: In my question,'&' means Bitwise AND.
    ");
    	system("pause");
    	printf("Lets play the game!!!
    Please choose your number x.
    ");
    	system("pause");
    	For(i,0,3){
    		printf("question %d:  x & %d = %d ?
    ",++cnt,(1<<i),(1<<i));
    		cin>>ans;
    		if(ans) x|=(1<<i);
    	}
    	printf("qustion %d:  x & 7 = %d ?
    ",++cnt,x&7);
    	cin>>ans;
    	if(ans){
    		printf("qustion %d:  x & 8 = %d ?
    ",++cnt,x&8);
    		cin>>ans;
    		if(ans){ output(); return 0; }
    		else{
    			printf("qustion %d:  x & 8 = %d ?
    ",++cnt,x&8);
    			cin>>ans;
    			if(!ans) x^=8;
    			output();
    			return 0;
    		}
    	}
    	else{
    		printf("qustion %d:  x & 3 = %d ?
    ",++cnt,x&3);
    		cin>>ans;
    		if(ans){
    			printf("qustion %d:  x & 4 = %d ?
    ",++cnt,x&4);
    			cin>>ans;
    			if(!ans) x^=4;
    			output();
    			return 0;
    		}
    		else{
    			printf("qustion %d:  x & 1 = %d ?
    ",++cnt,x&1);
    			cin>>ans;
    			if(ans) x^=2;
    			else x^=1;
    			output();
    			return 0;
    		}
    	}
    	return 0;
    }
    

    更多

    这题应该还有更多更妙的解法,希望有不同解法的人能在评论区分享一下,或者私信我。

  • 相关阅读:
    如何调用ActiveX网页中的JavaScript函数
    VC++开发的ActiveX如何加入安全机制,避免IE中提示“在此页上的ActiveX控件和本页上的其他部分的交互可能不安全,你想允许这种交互吗?”
    ActiveX多线程回调JavaScript
    JavaScript脚本如何访问VC++开发的ActiveX中的方法
    ActiveX异步回调JavaScript
    com/atl套间编程中如何实现定时invoke容器中的方法
    VC++开发的ActiveX如何通过JavaScript脚本和EOS应用交互
    thread wrapper
    最新Mysql中文帮助
    如何避免重复的http请求
  • 原文地址:https://www.cnblogs.com/Knowledge-Pig/p/13872620.html
Copyright © 2020-2023  润新知