zoukankan      html  css  js  c++  java
  • 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显示“运行超时”。

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

  • 相关阅读:
    【C语言天天练(三)】typedef具体解释
    操作系统之基本分页存储管理方式
    线索二叉树创建及删除
    SVN:This client is too old to work with working copy…解决的方法
    android4.2 telephone应用层分析
    JPA学习笔记(3)——JPA注解
    Android研发中对String的思考(源代码分析)
    《Effective Modern C++》翻译--条款2: 理解auto自己主动类型推导
    “2014年CityEngine三维建模与设计精英培训班”——全国巡回举办
    Git命令总结
  • 原文地址:https://www.cnblogs.com/heyour/p/12245386.html
Copyright © 2011-2022 走看看