【PAT甲级题解记录】1148 Werewolf - Simple Version (20 分)
前言
Problem:1148 Werewolf - Simple Version (20 分)
Tags:模拟
Difficulty:
剧情模式想流点汗想流点血死而无憾Address:1148 Werewolf - Simple Version (20 分)
问题描述
在一场狼人杀游戏中有2头狼,其余均为人,每名玩家都有一条发言说另一个玩家的身份,其中分别有一头狼和一个人说的话是错误的。其他均指认正确。
求哪俩个玩家是狼(输出编号靠前的情况)。
这个问题描述很奇怪,“Given that there were 2 werewolves among them, at least one but not all the werewolves were lying”,即“其中有两个狼人,至少有一个但不是所有的狼人在撒谎”,那不就是一个狼人在撒谎吗😓。
解题思路
这道题有两种思路,一种是二层循环遍历假设确认i、j为两个说假话的人,另一种是二层循环假设遍历确认i、j为狼。
- 若先假设已确认说假话的人:好处是可以迅速的知道当前所有话的真假供判断指认出来的玩家的身份,容易想到,但问题在于指认的信息是不全的,可能没有狼被指认出来,一开始我用了这种方法搞了半天还错了6分。
- 若先假设已确认是狼的两个玩家:好处是狼的身份都确定了,只要判断是不是合乎题意就可以输出,坏处是不好判断发言的真假情况,但既然知道了哪些是狼,也就知道了哪些是人,在根据玩家们的发言就能确认所有玩家说的是真话还是假话了。
- 这道题要是以为第一种思路简单直接上手做容易死掉可能上来第一道就做到自闭,但是想清楚后用第二种方法做就会很简单。
参考代码
/** @Author: Retr0.Wu* @Date: 2022-02-21 20:58:48* @Last Modified by: Retr0.Wu* @Last Modified time: 2022-02-22 00:04:30*/
#include <bits/stdc++.h>
using namespace std;
int main()
{int N;cin >> N;vector<int> said(N + 1);for (int i = 1; i <= N; i++){cin >> said[i]; // + human - wolf}for (int a = 1; a <= N; a++){for (int b = a + 1; b <= N; b++){// 当前确定ab为狼,根据所有玩家的发言判断说谎的狼数和人数int lie_w = 0, lie_h = 0;for (int i = 1; i <= N; i++){if (i == a || i == b) // 是一个狼,判断他有没有lie{if (said[i] > 0 && (said[i] == a || said[i] == b)) // 说狼是人 (注意要先判断said正负)lie_w++;else if (said[i] < 0 && -said[i] != a && -said[i] != b) // 说人是狼lie_w++;}else // 是一个人,判断他有没有lie{if (said[i] > 0 && (said[i] == a || said[i] == b)) //lie_h++;else if (said[i] < 0 && -said[i] != a && -said[i] != b)lie_h++;}}// 得到说谎情况,根据题意判断if (lie_w == 1 && lie_h == 1) //{cout << a << " " << b << endl;return 0;}}}cout << "No Solution" << endl;return 0;
}
总结
这道题要是以为第一种思路简单直接上手做容易死掉可能上来第一道就做到自闭,但是想清楚后用第二种方法做就会很简单。所以做之前真的要想清楚思路的合理性与实现效率,一股脑开题做不出不要紧,但是打乱了整场节奏就有大问题了。