2

题目大意:

已知 N 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家,如果有解,在一行中按递增顺序输出 2 个狼人的编号;如果解不唯一,则输出最小序列解;若无解则输出 No Solution.

算法思路:

题意不太好理解,此题没有考察任何算法技巧,是一个模拟题,重点在于根据给定的信息假设一个确定条件,在搜索过程中,出现同时符合第二个条件的就是解,具体来说就是,题目给定了2个确定的条件,第一个就是有且仅有2个狼人,第二个就是有2人说谎,一个是狼人,一个是平民。题目既然要求给出狼人的编号,那么搜索的全体空间就是所有人,由于狼人有2个,所以得使用双重循环搜索所有狼人,分别使用i和j代表2个狼人的编号(i<=j)。既然现在确定了狼人的编号,就说明第一个确定条件已经使用,现在就是需要知道怎么知道一个人有说谎了,其实也很简单,每次搜索的时候,我们给所有人一个初始状态,均为1,表示平民,让i和j为-1表示狼人,如果有一个人k说的话指定的那个人的状态a[k]与其现在本身的状态不一致就说明k在说谎。具体的做法就是,使用state初始化为1,state[i] = state[j] = -1;遍历每一个人的编号,只要a[k]*state[abs(a[k])]<0(a[k]为k所说的那个人的身份),就说明k在说谎,记录下来,添加进liars中,只要liars.size()==2&&state[liars[0]]+state[liars[1]]==0,说明现在找到一个解,由于是从前往后搜索得到的结果,编号一定是最小的,直接退出循环。

考场上要是遇见这个题,心态可能得崩溃。

提交结果:

image.png

AC代码:

#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

int main(){
    int N;
    scanf("%d",&N);
    int a[N+1];
    for (int i = 1; i <= N; ++i) {
        scanf("%d",&a[i]);
    }
    // 暴力搜索,遍历所有的狼人,找到2个说谎的人,一人是平民,一人是狼人
    for (int i = 1; i <= N; ++i) {
        for (int j = i+1; j <= N; ++j) {
            // 首先初始化每一个人的状态,假设都是平民
            int state[N+1];
            fill(state,state+N+1,1);
            //(i,j)是一对狼人
            state[i] = state[j] = -1;
            // 只要当前人说的话与那个人的身份不符合,说明在说谎
            vector<int> liars;
            state[i] = state[j] = -1;
            for (int k = 1; k <= N; ++k) {
                if(a[k]*state[abs(a[k])]<0){
                    //k在说谎,记录下来
                    liars.push_back(k);
                }
            }
            if(liars.size()==2&&state[liars[0]]+state[liars[1]]==0){
                // 找到一组解
                printf("%d %d",i,j);
                return 0;
            }
        }
    }
    printf("No Solution");
    return 0;
}


乔梓鑫
569 声望17 粉丝

主要分享个人学习经验和心得