猜猜猜 猜名次 猜一個兇手

猜名次

5位運動員參加了10米臺跳水比賽,有人讓他們預測比賽結果:

A選手說:B第二,我第三;
B選手說:我第二,E第四;
C選手說:我第一,D第二;
D選手說:C最後,我第三;
E選手說:我第四,A第一;
比賽結束後,每位選手都說對了一半,請編程確定比賽的名次。

int main()
{
	//窮舉法
	int a = 1;
	for (; a <= 5; a++)
	{
		int b = 1;
		for (; b <= 5; b++)
		{
			int c = 1;
			for (; c <= 5; c++)
			{
				int d = 1;
				for (; d <= 5; d++)
				{
					int e = 1;
					for (; 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 
							)


						{
							unsigned char flag = 0;
							flag |= 1 << (a - 1);
							flag |= 1 << (b - 1);
							flag |= 1 << (c - 1);
							flag |= 1 << (d - 1);
							flag |= 1 << (e - 1);


							//檢測flag 是否連續


							while (flag)
							{
								if (flag & 1)//檢測最末位是否爲1
								{
									flag >>= 1;
								}
								else
								{
									break;
								}
							}


							if (!flag)
							{
								printf("a=%d b=%d c=%d d=%d e=%d\n", a, b, c, d, e);
							}
						}


					}
				}
			}
		}
	}
	system("pause");
	return 0;
}

如果要求比賽名次不能並列
及更改以下條件即可

if (flag==0x1f)
{
printf("a=%d b=%d c=%d d=%d e=%d\n", a, b, c, d, e);
}

解釋:
如果不能並列 flag=0001 1111 =0x1f

思路整理

通過窮舉法(用循環)表示出來 a b c d e 所有可能的取值。
第一步:
根據題意 一個的說的話中一半是正確的一半是錯誤的 ,用表達式(b ==2) + (a ==3) == 1表示 。注意 +的優先級高於== 應加上()
第二步:
設立falg flag 的每一位代表一個名次 現實生活中不允許出現都是第五名 沒有第一名,或者說三個第一 之後從第三名開始,這樣的斷層情況。因此需要對flag 進行檢測。檢測1 是否連續 。

檢測末尾爲1 的方法 flag & 1
如果flag 不爲 0 且沒有斷層 進行 移位操作之後, flag=0 結束循環跳出
如果flag 不爲 0 但是檢測到有斷層 跳出

最後跳出結果 當flag=0 的就是答案。

猜兇手

日本某地發生了一件謀殺案,警察通過排查確定殺人兇手必爲4個嫌疑犯的一個

以下爲4個嫌疑犯的供詞:

A說:不是我。

B說:是C。

C說:是D。

D說:C在胡說

已知3個人說了真話,1個人說的是假話。

現在請根據這些信息,寫一個程序來確定到底誰是兇手

void Findkiller()
{//A說:不是我。
 //	B說:是C。
 //	C說:是D。
 //	D說:C在胡說
 //	已知3個人說了真話,1個人說的是假話。*/

	//假定一個是兇手
	char  killer = 'A';
	for (; killer <= 'D'; killer++)
	{
		//printf("%c\n",killer);

    //killer!='A'
	//killer =='C'
	//killer =='D'
	//killer!='D'
		if ((killer != 'A') + (killer == 'C') + (killer == 'D') + (killer != 'D') == 3)
			printf("find killer is %c\n", killer);
	}

}


思路整理

不難發現,在c 和d 兩個人中出現了矛盾。 c 和d 不可能說的都是真話。因此 兩人中必有一人說的是假話,所以b 說的是真的,兇手是c
將四個人說的話用表達式表示出來
//killer!='A' //killer =='C' //killer =='D' //killer!='D'
假定兇手是a 是b是 c是 d
在字符中 a b c d 是連續的 ,可以通過++ 來依次往後
所以用循環來判斷
看看哪一個假設滿足上面的條件。

以下寫法不推薦

	//A說:不是我。
	//B說:是C。
	//C說:是D。
	//D說:C在胡說
	//已知3個人說了真話,1個人說的是假話。

	int a = 0;
	for (; a <= 1; a++)
	{
		int b = 0;
		for (; b <= 1; b++)
		{
			int c = 0;
			for (; c <= 1; c++)
			{
				int d = 0;
				for (; d <= 1; d++)
				{
					if (a + b + c + d == 3)
					{

						//printf("a=%d b=%d c=%d d=%d\n", a, b, c, d);

						if (c + d != 2&&c==0) //其實很容易發現c 和d 是矛盾的,所以兩個人不可能說的都是真話,所以c+d==1
						{
							printf("a=%d b=%d c=%d d=%d\n", a, b, c, d);
							printf("is c\n");
							
						}
					}
				}
			}
		}
	}

這個做法其實和上面的猜名詞是類似的,但是代碼不夠精簡
並且在這個if (c + d != 2&&c==0)條件的地方
c+d!=2可以解釋清楚
而 c==0 其實是 寫程序的人已經判斷出來 c 說的是假話(b 說的是正確的)
這個代碼是完全根據答案寫出來的。是有一點往裏面湊正確結果的意思。

如果不加 c==0

結果就是這個。
在這裏插入圖片描述
其實也可以看出 程序中的這條語句
printf(“is c\n”);
== 很明顯的就是 從答案出發 寫的程序==
這種做法其實是有一點投機取巧的。不能算是一個好方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章