题目连接:https://pintia.cn/problem-sets/994805260223102976/problems/1038429385296453632
以下文字摘自《灵机一动·好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中,1 号玩家说:“2 号是狼人”,2 号玩家说:“3 号是好人”,3 号玩家说:“4 号是狼人”,4 号玩家说:“5 号是好人”,5 号玩家说:“4 号是好人”。已知这 5 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。扮演狼人角色的是哪两号玩家?
本题是这个问题的升级版:已知 N 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家?
输入格式:
输入在第一行中给出一个正整数 N(5)。随后 N 行,第 i 行给出第 i 号玩家说的话(1),即一个玩家编号,用正号表示好人,负号表示狼人。
输出格式:
如果有解,在一行中按递增顺序输出 2 个狼人的编号,其间以空格分隔,行首尾不得有多余空格。如果解不唯一,则输出最小序列解 —— 即对于两个序列 [ 和 [,若存在 0 使得 [ (i≤k),且 [,则称序列 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
最终AC代码如下(参考链接:https://blog.csdn.net/liuchuo/article/details/82560831):
#include#include #include using namespace std; int main(){ int n; cin>>n; vector<int> lie, vi(n+1); //声明一个初始大小为n+1的向量 for(int i=1; i<=n; i++) { cin>>vi[i]; } for(int i=1; i ){ for(int j=i+1; j<=n; j++){ vector<int> ans(n+1, 1); //声明一个初始大小为n+1且初始值都为1的向量 lie.clear(); ans[i] = -1; //-1表示狼人 1表示好人 ans[j] = -1; for(int k=1; k<=n; k++) { if(vi[k] * ans[abs(vi[k])] < 0){ lie.push_back(k); } } if(lie.size()==2 && ans[lie[0]]+ans[lie[1]]==0){ cout<" "< endl; return 0; } } } cout<<"No Solution"<<endl; return 0; }
主要思路是:穷举法。首先将每个人说的话(输入的信息)记录在vi向量中,并假设i、i+1(i从1开始)均是狼人,那么其余人都是好人(分别用-1和1表示),存储在ans向量中。之后检验一下假设的情况与实际情况是否相符合且是否满足题干:一个狼人一个好人说谎,由于i本来就是按序号从小到大遍历,因此得到满足条件的情况就可以输出之并结束程序。
记录本题是想反思一下做题思路的问题。首先看到这题时,我是比较蒙的,感觉无从下手。我按着固有的分析方式进行如下假设:
输入:
5 -2 +3 -4 +5 +4
对应着便是:
编号: 1 2 3 4 5 话: -2 +3 -4 +5 +4
那么1、3两个编号的人必须有一个人说谎了,且有一个人必定是狼人。于是就可以分为 编号1说谎且是狼人, 编号1说谎且是好人, 编号3说谎且是狼人, 编号3说谎且是好人 四种情况。然后在基于该条件下,进行进一遍推理,直到推出矛盾的结果。思路真的很奇怪,我也不知道为什么一看见这题,会这样思考,也许是慌不择路了。然而按着这种思路写程序是根本写不出的,思路太混乱太复杂了。
看了别人博客的分析后,豁然明白了一个道理:人的智慧在于思维,可以对问题进行推理,在进行少量尝试后得到答案;而程序的智慧在于计算,可以短时间内计算完所有有限数量的结果,但判断的逻辑不能太复杂。这也启示,在时间复杂度允许的情况下,那么可以穷举各种情况进行简单判断,而不是设置多种条件来过滤答案。
此外,还有值得学习的一个方面,是vector这个向量容器的使用,具体可以参看大佬的博客:https://www.cnblogs.com/YJthua-china/p/6550960.html
这里,我想提示一下,若程序如下这样写可能某些情况下查不出错误,但是放在OJ上运行时会提示“运行时错误”。
vector<int> lie, vi(n+1); //声明一个初始大小为n+1的向量 cin>>n;
for(int i=1; i<=n; i++){
cin>>vi[i];
}
写程序时,不小心犯了这种低级错误:先声明了向量vi,然后再输入n的值。在运行题干第一个测试用例时,正常出结果;然而运行第二个测试用例时,没有任何输出直接结束了。在OJ上运行,测试用例1和3显示“运行超时”。
正确的写法应该是将第二行写在第一行前面。