B1089 狼人杀-简单版

题目连接: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 使得 [ (ik),且 [,则称序列 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 <iostream>
#include <vector>
#include <cmath>
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<n; 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<<i<<" "<<j<<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显示“运行超时”。

正确的写法应该是将第二行写在第一行前面。

posted @ 2020-01-31 14:49  已是夕阳,不如放下  阅读(371)  评论(0编辑  收藏  举报