1. 順位を推測する
必須:
5 人の選手が 10 メートルの飛び込み競技に参加し、誰かが彼らに競技の結果を予想するよう求めました。
プレーヤー A は、「B は 2 番目、私は 3 番目です。
プレーヤー B は、「私は 2 位、E は 4 位です。
プレーヤー C は、「私が 1 位、D が 2 位です」と言いました。
プレーヤー D は次のように言いました。C が最後で、私は 3 番目です。
プレーヤー E は次のように言いました: 私は 4 番目、A は 1 番目です。
ゲーム終了後、各プレイヤーは半分正解しました。ゲームの順位を決定するようにプログラムしてください。
アイデア:
全員が 1 番目から 5 番目まで進むと、合計 5^5 の可能性があり、これを完了するには 5 層のサイクルだけが必要です。ただし、重複チェックをしていないため思わぬ結果になるため、2位が2人、3位が3人というように2人以上で順位を競う状況が発生するため、条件を満たしていても5人の順位が重複していないかを確認する必要があり、これを関数に渡して実行し、5人の順位が同点であれば0を返し、そうでなければ1を返す。
最初の解決策:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
int A = 0;
int B = 0;
int C = 0;
int D = 0;
int E = 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++) {
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) {
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;
}
2 番目の解決策:
#include <stdio.h>
int checkData(int *p)
{
int tmp[7] = { 0 }; //标记表,实际是哈希表的思路。一开始每个元素都是0。
int i;
for (i = 0; i < 5; i++)
{
if (tmp[p[i]]) //如果这个位置的标记已经是1,则代表重复,直接返回0。
{
return 0;
}
tmp[p[i]] = 1; //如果不是,则给这个位置标记为1。
}
return 1; //全部标记完毕也没有出现重复的情况,代表OK。
}
int main()
{
int p[5]; //0 1 2 3 4分别代表a b c d e
for (p[0] = 1; p[0] <= 5; p[0]++)
{
for (p[1] = 1; p[1] <= 5; p[1]++)
{
for (p[2] = 1; p[2] <= 5; p[2]++)
{
for (p[3] = 1; p[3] <= 5; p[3]++)
{
for (p[4] = 1; p[4] <= 5; p[4]++) //五层循环遍历
{
//这里是五个人的描述,由于比较表达式只有0和1两个结果,如果要两个条件有且只有一个为真,则可以用比较表达式的值总和为1的方式直接判定。别忘了还要判定不能并列。
if ((p[1] == 2) + (p[0] == 3) == 1 && //B第二,我第三
(p[1] == 2) + (p[4] == 4) == 1 && //我第二,E第四
(p[2] == 1) + (p[3] == 2) == 1 && //我第一,D第二
(p[2] == 5) + (p[3] == 3) == 1 && //C最后,我第三
(p[4] == 4) + (p[0] == 1) == 1 && //我第四,A第一
checkData(p) //不能并列
)
{
for (int i = 0; i < 5; i++)
{
printf("%d ", p[i]);
}
putchar('\n');
}
}
}
}
}
}
return 0;
}
3 番目の解決策:
#include <stdio.h>
void swapArgs(int * a, int * b) //交换函数
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void diveRank(int * p, int n)
{
if(n >= 5) //此时的n也是用来控制循环层数的。
{
if ((p[1] == 2) + (p[0] == 3) == 1 && //B第二,我第三
(p[1] == 2) + (p[4] == 4) == 1 && //我第二,E第四
(p[2] == 1) + (p[3] == 2) == 1 && //我第一,D第二
(p[2] == 5) + (p[3] == 3) == 1 && //C最后,我第三
(p[4] == 4) + (p[0] == 1) == 1) //我第四,A第一
//由于此时是执行的全排列,所以查重也省了。
{
for (int i = 0; i < 5; i++)
{
printf("%d ", p[i]);
}
putchar('\n');
}
return;
}
int i;
for(i = n; i < 5; i++) //这个递归方式就完成了对1~5的全排列,方法是从后向前不停的执行交换。可以参考改进二和原代码,将这个递归程序写回成循环后,可以更好的理解。
{
swapArgs(p + i, p + n);
diveRank(p, n + 1);
swapArgs(p + i, p + n);
}
}
int main()
{
int p[5] = { 1, 2, 3, 4, 5 }; //当然由于是全排列,所以初值必须给好。
diveRank(p, 0);
return 0;
}
結果:
ランキング: 1 2 3 4 5
選手: B D A E C
2. 殺人犯を推測する
日本の某所で殺人事件が発生し、警察は捜査の結果、犯人は容疑者4人のうちの一人であると断定した。
容疑者4人の自白は以下の通り。
A は言いました:私ではありません。
Bは言いました:Cです。
C は言いました: はい D.
D は言いました: C はナンセンスなことを話しています
3人が真実を語り、1人が嘘をついたことがわかっている。
では、この情報に基づいて殺人犯が誰であるかを判断するプログラムを書いてください。
最初の解決策:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
int A = 0;
int B = 0;
int C = 0;
int D = 0;
for (int A = 0; A <= 1;A++) {
for (int B = 0; B <= 1;B++) {
for (int C = 0; C <= 1;C++) {
for (int D = 0; D <= 1;D++) {
if ((A != 1) + (C == 1) + (D == 1) + (D != 1) == 3) //假设为1时是凶手
if (A + B + C + D == 1) {
printf("A=%d B=%d C=%d D=%d\n", A, B, C, D);
if (A == 1)
printf("A是凶手");
else if (B == 1)
printf("B是凶手");
else if (C == 1)
printf("C是凶手");
else
printf("D是凶手");
}
}
}
}
}
return 0;
}
2 番目の解決策:
#include<stdio.h>
int main()
{
int killer = 0;
//分别假设凶手是a,b,c,d,看谁是凶手时满足3个人说了真话,一个人说了假话
for (killer = 'a'; killer <= 'd'; killer++)
{
if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
printf("凶手是:%c", killer);
}
return 0;
}
結果:
Cは殺人者