邏輯推理典例:根據資訊排名次
邏輯推理在生活中處處可見,它有助於我們鍛鍊自己的思維
這裡有這樣一道很經典的邏輯推理題,看似簡單裡面卻暗藏很多陷阱,往往大多數人都得到的是不完全正確的答案;
讓我們來分析一下這道典例
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;
}