1. 程式人生 > >1089 狼人殺-簡單版——C/C++實現

1089 狼人殺-簡單版——C/C++實現

題目

1089 狼人殺-簡單版 (20 point(s))

以下文字摘自《靈機一動·好玩的數學》:“狼人殺”遊戲分為狼人、好人兩大陣營。在一局“狼人殺”遊戲中,1 號玩家說:“2 號是狼人”,2 號玩家說:“3 號是好人”,3 號玩家說:“4 號是狼人”,4 號玩家說:“5 號是好人”,5 號玩家說:“4 號是好人”。已知這 5 名玩家中有 2 人扮演狼人角色,有 2 人說的不是實話,有狼人撒謊但並不是所有狼人都在撒謊。扮演狼人角色的是哪兩號玩家?

本題是這個問題的升級版:已知 N 名玩家中有 2 人扮演狼人角色,有 2 人說的不是實話,有狼人撒謊但並不是所有狼人都在撒謊。要求你找出扮演狼人角色的是哪幾號玩家?

輸入格式:

輸入在第一行中給出一個正整數 N(5≤N≤100)。隨後 N 行,第 i 行給出第 i 號玩家說的話(1≤i≤N),即一個玩家編號,用正號表示好人,負號表示狼人。

輸出格式:

如果有解,在一行中按遞增順序輸出 2 個狼人的編號,其間以空格分隔,行首尾不得有多餘空格。如果解不唯一,則輸出最小序列解 —— 即對於兩個序列 A=a[1],...,a[M] 和 B=b[1],...,b[M],若存在 0≤k<M 使得 a[i]=b[i] (i≤k),且 a[k+1]<b[k+1],則稱序列 A 小於序列 B。若無解則輸出 No Solution

輸入樣例 1:

5
-2
+3
-4
+5
+4

輸出樣例 1:

1 4

輸入樣例 2:

6
+6
+3
+1
-5
-2
+4

輸出樣例 2(解不唯一):

1 5

輸入樣例 3:

5
-2
-3
-4
-5
-1

輸出樣例 3:

No Solution

演算法

這道題目很長,剛開始拿到,感覺無從下手,不知道如何分析……後來去看了別人的演算法思想,還是不太理解,晚上畢業的博士師姐請吃飯,回來又看了電影《死侍》,剛才認真看了分析,終於看懂了。。。考試碰到類似的題目,一點思路都沒有,才要頭皮發麻……崩潰!!!

起初讀完題目知道題目的意思是這樣的:

  1. N個人有兩個狼人,有2個說謊者;
  2. 2個說謊者中一個是狼人,一個是好人;

但是還是沒有具體的思路,後來看懂之後感覺其實也挺簡單。思路是這樣的:由於不知道誰是狼人,因此可以採用計算思維 ,逐個進行驗證,反正不缺算力,這對於習慣公式和推導的非計算機專業的理工科學生有時候真的想不到……

首先將資料存起來,存入vector型陣列v(n+1),設定i/j兩個變數是狼人,i從1~n(由於很多參考演算法採用vector都是從1開始儲存的,因此也就從1~n了,從0~n-1也是一樣的,只不過1~n比較方便),是外層for迴圈,j從i+1~n,是內層for迴圈。迴圈之前,先申請個vector陣列a(N+1,1),也就是n+1個數組元素的值都是1,這裡a陣列元素的值為1表示是好人,為-1表示是狼人,因此由於我們用i,j表示狼人,還需要將a[i]=a[j]=-1才行。同時還需要申請一個lie的vector,因為要往裡面存入說謊者,由於不知道有幾個,因此直接用vector就好,不用vector陣列。這裡顯示了vector作為C++中動態陣列的好處了,妙呀!!!如果有說謊者就存入lie,利用lie.push_back()就可以。

下面就需要知道如何判斷說謊者的條件:

  1. 自己說別人是狼人(v[k]<0),然而別人並不是狼人(a[abs(v[k])] == 1)
  2. 自己說別人不是狼人(v[k]>0),然而別人就是狼人(a[abs(v[k])] == -1)
  3. 即:v[k]*a[abs(v[k])] < 0

只要指定判斷說謊者的條件,即兩個說謊者且其中一個為狼人(lie.size()==2&&a[lie[0]]+a[lie[1]]==0),滿足此條件輸出即可。由於遍歷的順序是從1~n,自然會滿足最小序列的要求。滿足條件輸出此時的 i,j(我們之前不是讓他倆當狼嘛~~~),如果都不滿足,輸出 No Solution。

程式碼

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main(){
	int n;	cin>>n;
	vector<int> v(n+1);
	for(int i=1;i<=n;i++)	cin>>v[i];
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			vector<int> lie,a(n+1,1);
			a[i]=a[j]=-1;
			for(int k=1;k<=n;k++)
				if(v[k]*a[abs(v[k])]<0)	lie.push_back(k) ;
			if(lie.size() ==2&&a[lie[0]]+a[lie[1]]==0){
				cout<<i<<" "<<j;
				return 0;
			}
		}	
	}
	cout<<"No Solution";
	return 0;
}