逻辑推理典例:根据信息排名次

逻辑推理在生活中处处可见,它有助于我们锻炼自己的思维

这里有这样一道很经典的逻辑推理题,看似简单里面却暗藏很多陷阱,往往大多数人都得到的是不完全正确的答案;


让我们来分析一下这道典例

5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次

解题思路:

1.看到这种题,我们首先需要把所有结果都陈列出来,然后对每一次结果进行判断,然后对不符合条件的排名情况舍弃,最终就能得到我们的正确名次;

2.对于每位选手只说对了一半我们该如何来判断呢?

例如对于A选手,我们如何判断他说对了一半?
有人会立马想到:if ( b == 2 || a== 3)
这无疑是有漏洞的:b==2和a==3都成立这条件也为真,然而题目只需要有且只能说对一半;

然后会有人想到:if ( (b == 2 || a== 3) == 1  && (b == 2 && a== 3)==0 )
对,这能满足题目的需求,达到只能说对一半的要求,但这样写是否过于复杂了?
下面介绍一种最优的解法:
if((b == 2) + (a == 3) == 1);

3.在做这道题时,我们得先了解一个常识,这也是本题的关键和陷阱所在。在排名中我们来列举如下情况:

 1.  a、b、c、d、e的名次为  1,2,3,4,5;
 2.  a、b、c、d、e的名次为  1,1,3,4,5;
 3.  a、b、c、d、e的名次为  1,1,2,3,2;
 4.  a、b、c、d、e的名次为  1,3,3,4,5;
其中哪些排名是不可能的呢?
2和4的排名是不可能出现的。生活实际中,排名是可以重叠的(两个或多个并列一个名次),但不能跨级,意思是,有第一名,没第二名,却有第三名,这样的情况你在生活实际中遇到过吗?肯定是不可能的
所以,我们在判断排名是否合格时要排除跨级的这种情况。
那么难点来了,如何判断这五个人的排名是否跨级了
解法:我们将这五个人的名次都放到 flag 变量(初始化为零)的比特位中,如果出现第一名,就让第一个比特位(从右往左)置一,如果出现了第二名,就让第二个比特位置一,.......    然后我们来判断flag从右往左如果比特位之间有零,则不符合要求(即比特位从右往左不能出现1 0 1 这种序列

下面呈上源码:

#include<stdio.h>
/*5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。 */

//注意:续航符打出后需直接回车,然后再写代码,回车前回车会不能有空格,否则就会有警告
//注意:续航符后面不能加注释,否则直接报错 
int main()
{
	int a,b,c,d,e;
	int flag = 0;
	for (a = 1; a <= 5; a++)
		for (b = 1; b <= 5; b++)
			for (c = 1; c <= 5; c++)
				for (d = 1; d <= 5; d++)
					for (e = 1; e <= 5; e++)
					{
						flag = 0;
						if ((b == 2) + (a == 3) == 1 && \
						(b == 2) + (e == 4) == 1 && \
						(c == 1) + (d == 2) == 1 && \
						(c == 5) + (d == 3) == 1 && \
						(e == 4) + (a == 1) == 1)
							{
								flag |= 1 << (a-1);
								flag |= 1 << (b-1);
								flag |= 1 << (c-1);
								flag |= 1 << (d-1);
								flag |= 1 << (e-1);
								while (flag)
								{
									if (!(flag&1))
									break;
									flag >>= 1;
								}
								if (flag == 0)
								{
									printf("a:%d  b:%d  c:%d  d:%d  e:%d\n", a, b, c, d, e);
								}
							}
					} 
	return 0;
}

我在写这段代码时用到了续航符 \ ,然后总是有警告和错误,经百度后总结如下:
续航符后面不能有注释,否则会报错;
续航符打出后需直接回车,然后再写代码,回车前回车会不能有空格,否则就会有警告;

猜你喜欢

转载自blog.csdn.net/eternal_yangyun/article/details/83961843