题目一:求名次
题目详情:
5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果:
- A选手说:B第二,我第三;
- B选手说:我第二,E第四;
- C选手说:我第一,D第二;
- D选手说:C最后,我第三;
- E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。
解题思路:
本题的关键在于,如何把上面 5 55 位运动员说的话转换为编程语言。以A选手说的 “B第二,我第三” 为例,我们可以Y用代码表示成:B==2;A==3 。但是后面又说:“每位选手都说对了一半”。这说明A选手也只说对了一半,也就是说B==2;A==3只有一个是真的,在这里真的用 1 11 来表示,假的用 0 00 来表示,因此B==2加A==3的结果一定等于 1 11 ,可以用代码表示为:(B==2)+(A==3)==1,但这只表示A选手所说的,五位选手都只说对了一半应该表示为:((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),这就是五个人名次应该满足的条件。此时我们只需要列举出五个人名次的所有情况,然后看哪种情况满足上面的条件。我们可以通过for循环的嵌套来得到五人名词的所有情况。分析的差不多了,接下来上代码
int main() { int A = 0; int B = 0; int C = 0; int D = 0; int E = 0; for (A = 1; A <= 5; A++)//通过for循环的嵌套得到五人名次的所有可能 { for (B = 1; B <= 5; B++) { for (C = 1; C <= 5; C++) { for (D = 1; D <= 5; D++) { for (E = 1; E <= 5; E++) { if (((B == 2) + (A == 3) == 1) //A说的 && ((B == 2) + (E == 4) == 1) //B说的 && ((C == 1) + (D == 2) == 1) //C说的 && ((C == 5) + (D == 3) == 1) //D说的 && ((E == 4) + (A == 1) == 1))//E说的 { printf("A=%d B=%d C=%d D=%d E=%d\n", A, B, C, D, E); } } } } } } return 0; }
代码执行结果:
这里代码的结果给出了很多种满足条件的名次,但是仔细观察可以发现:有很多组排名都出现了在同一组中一个名次出现了多次,以第一行的结果为例,名次 1 11 就出现了三次,这显然是不符合要求的。第 1 、 2 、 3 、 4 、 5 1、2、3、4、51、2、3、4、5 名分别只能被 A、B、C、D、E中的一个占据。因此我们需要添加一个限制条件去除掉同组中一个名次出现多次的这些情况。那这个条件是什么呢?我们不难发现,虽然A、B、C、D、E都应该对应着不同的名次,但都逃不掉是 1 、 2 、 3 、 4 、 5 1、2、3、4、51、2、3、4、5 其中的一个名次。因此无论A、B、C、D、E五个人的名次如何, A ∗ B ∗ C ∗ D ∗ E A*B*C*D*EA∗B∗C∗D∗E都逃不掉等于 1 ∗ 2 ∗ 3 ∗ 4 ∗ 5 = 120 1*2*3*4*5=1201∗2∗3∗4∗5=120。A*B*C*D*E==120就是我们需要添加的限制条件。修改后的代码如下:
int main() { int A = 0; int B = 0; int C = 0; int D = 0; int E = 0; for (A = 1; A <= 5; A++)//通过for循环的嵌套得到五人名次的所有可能 { for (B = 1; B <= 5; B++) { for (C = 1; C <= 5; C++) { for (D = 1; D <= 5; D++) { for (E = 1; E <= 5; E++) { if (((B == 2) + (A == 3) == 1) //A说的 && ((B == 2) + (E == 4) == 1) //B说的 && ((C == 1) + (D == 2) == 1) //C说的 && ((C == 5) + (D == 3) == 1) //D说的 && ((E == 4) + (A == 1) == 1))//E说的 { if (A * B * C * D * E == 120)//限制条件:避免一组中同一名次出现多次 { printf("A=%d B=%d C=%d D=%d E=%d\n", A, B, C, D, E); } } } } } } } return 0; }
最终结果:
此时我们就得到了A、B、C、D、E五个人的名次。
题目二:找凶手
题目详情:
日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。
以下为4个嫌疑犯的供词:
- A说:不是我。
- B说:是C。
- C说:是D。
- D说:C在胡说
已知3个人说了真话,1个人说的是假话。
现在请根据这些信息,写一个程序来确定到底谁是凶手。
解题思路:
遇到这种问题我们通常都是用假设排除法来解决,依次假设A、B、C、D为凶手,然后看四个人所说的是否满足 3 33 个真话,1 11 个假话。例如:先假设 A 为凶手,此时A说的 “ 不是我 ” 就是假话,B说的 “ 是C ” 也是假话,C说的 “ 是D ” 也是假话,D说的 “C在胡说 ” 是真话,此时在假设A是凶手的情况下出现了 3 33 句假话,1 11 句真话,不满足题目要求,说明A不是凶手。接下来该假设 B 是凶手了,具体分析就不再赘述。最终我们可以得出 C 是凶手。如何把以上分析过程转化为编程语言是我们现在需要面对的问题。
在上述分析过程中,我们首先对凶手进行了假设,因此在代码中我们首先应该定义一个变量killer用来表示凶手,并且需要让这个变量依次取到 A、B、C、D ,这个简单,可以通过 for 循环来实现,假设完凶手以后,这个凶手需要满足: A、B、C、D 四个人说的话中有 3 33 句真话,1 11 句假话这个条件。这个条件用代码可以表示为:(killer!='A') + (killer == 'C') + (killer == 'D') + (killer != 'D') == 3。分析的差不多了,接下来上代码:
int main() { char killer = 0; for (killer = 'A'; killer <= 'D'; killer++) { if ((killer!='A') + (killer == 'C') + (killer == 'D') + (killer != 'D') == 3)//四句话3真1假,真的用1表示,假的用0表示,所以这四个表达式的最终结果一定等于3 { printf("%c\n", killer); } } return 0; }
最终结果:
可见最终的凶手就是 C ,这和我们自己分析出来的结果是一样的。
好了,今天的分享就到这里啦,如果你有更好的思路或者方法,欢迎在评论区或者私信,给我留言,拜拜咯!