PAT B 1089 狼人杀-简单版(C语言)*两种思路

一、题目

以下文字摘自《灵机一动·好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中,1 号玩家说:“2 号是狼人”,2 号玩家说:“3 号是好人”,3 号玩家说:“4 号是狼人”,4 号玩家说:“5 号是好人”,5 号玩家说:“4 号是好人”。已知这 5 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。扮演狼人角色的是哪两号玩家?

本题是这个问题的升级版:已知 N 名玩家中有 2 人扮演狼人角色,有 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家?

输入格式:
输入在第一行中给出一个正整数 N(5 ≤ N ≤ 100)。随后 N 行,第 i 行给出第 i 号玩家说的话(1 ≤ i ≤ N),即一个玩家编号,用正号表示好人,负号表示狼人。

输出格式:
如果有解,在一行中按递增顺序输出 2 个狼人的编号,其间以空格分隔,行首尾不得有多余空格。如果解不唯一,则输出最小序列解 —— 即对于两个序列 A=a[1],…,a[M] 和 B=b[1],…,b[M],若存在 0≤k

输入样例 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

二、思路一:设i、j为狼人(二刷)

STEP1:初始化
state[ ] : 发言 ; Lier[ ] : 说谎者 ; nLier说谎者数 ; identity[ ] : 身份;
identity[]=1(狼人)/0(好人);
STEP2:判断
第一、二层for()循环,假设i、j为狼人:identity[i]=identity[j]=1,其余置0;
第三层循环:从0开始判断发言,若该玩家描述的玩家的身份与实际身份不符,则该玩家说瞎话,加入Lier[]数组;
若找到两名说谎者,且其一是狼,输出;

三、思路一代码实现

#include 
#include 
int main()
{
    int N;
    scanf("%d",&N);
    int state[N+1],identity[N+1],Lier[N+1],nLier;
    for(int i=1 ; i<=N ; i++)
        scanf("%d",&state[i]);
    for(int i=1 ; i<N ; i++)
        for(int j=i+1 ; j<=N ; j++)
        {
            for(int k=1 ; k<=N ; k++) identity[k]=Lier[k]=0;
            identity[i]=identity[j]=1,nLier=0;
            for(int k=1 ; k<=N && nLier<=2 ; k++)
                if( identity[ abs( state[k] ) ] != ( state[k] < 0 ) )
                    Lier[nLier++]=k;
            if( nLier == 2 && identity[ Lier[0] ] + identity[ Lier[1] ] == 1 )
            {
                printf("%d %d",i,j);
                return 0;
            }
        }
    printf("No Solution");
}

四、思路二:设i、j为说谎者(一刷)

这道题是在下想复杂了(流泪)
大概我是全网唯一一个,假设i、j是说谎者来做的吧(流Lui)
为什么大家假设i、j是狼看起来好方便(哭)
别问,问就是过年好
哈哈哈哈哈哈哈哈哈过年好!!
PAT B 1089 狼人杀-简单版(C语言)*两种思路_第1张图片
要不是数量小我觉得我铁超时…

主要思路:

设i、j说谎,若没有其他说谎者,且除i、j外最多一个狼和N-3个好人,且i、j一个不是好人一个不是狼。
1、一个数组State[]记录大家的发言,一个数组Identity[]记录发言所确定的身份,Identity[k]=1则k为好人,Identity[k]=-1则k为狼,Identity[k]=0则k身份不确定
2、假设i、j为说谎者,进行遍历:
若该玩家已被描述的身份和当前发言中不一致,既除i、j外另有人说谎,跳出;
除i或j外,有超过一个以上的狼,有N-3个以上的好人,则必然是错误解,跳出;
3,、若中途未跳出,且i、j一个不是好人一个不是狼,放入狼数组,用Min保存最小序列解。

最小序列解:两个元素组成的序列的最小序列,就像两位整数比大小:如12<35
高位不相等时:高位小者是小序列
高位相等时:比较次高位

五、思路二代码实现

#include 
#include 
int main()
{
    int i,j,k,N,nHuman,nWolf,Min=0,Count=0,Player,Idt;
    scanf("%d",&N);
    int State[N],Wolf[(N+1)*N/2][2];//玩家发言
    for(i=0 ; i<N ; i++)
        scanf("%d",&State[i]);
    for(i=0 ; i<N-1 ; i++)
        for(j=i+1 ; j<N ; j++)//假设i与j说了谎
        {
            int Identity[101]={0};//记录身份的数组
            for(nHuman=0,nWolf=0,k=0 ; k<N ; k++)//判断
            {
                Player = abs(State[k]);//玩家编号
                Idt = ( (k == i || k == j ) ? ( State[k] > 0 ? -1 : 1 ) : ( State[k] > 0 ? 1 : -1 ) );//身份
                if( Identity[Player] * Idt < 0)//与其他玩家发言描述身份不符,则有人说谎,存在矛盾。
                    break;
                if( Identity[Player] == 0 && Player != i+1 && Player != j+1 )//根据描述该玩家身份的第一次发言记录该身份出现次数。
                    Idt > 0 ? nHuman++ :  ( Wolf[Count][++nWolf] = Player ) ;//nWolf只记录i、j以外的狼和好人数目
                Identity[Player] = Idt;//将身份赋予玩家
                if( nWolf > 1 || nHuman >= N-2 )//若除i或j外,有超过一个以上的狼,有N-3个以上的好人,则必然是错误解
                    break;
            }
            if( k == N && Identity[i+1] * Identity[j+1] <=0 )
                //若中途未跳出循环,且i、j一个不是好人,一个不是狼,采集狼的数据
            {
                if( Identity[i+1] * Identity[j+1] == 0 )
                    Wolf[Count][0] = i+1;
                else
                    Wolf[Count][0] = j+1;
                if( nWolf == 0 )
                    for(int p=1 ; p<=N ; p++)
                        if( Identity[p] == 0 && p != i+1 && p != j+1 )
                        {
                            Wolf[Count][1]=p;
                            break;
                        }
                if( Wolf[Count][1] < Wolf[Count][0])//两狼升序排序
                {
                    int Temp = Wolf[Count][0];
                    Wolf[Count][0] = Wolf[Count][1];
                    Wolf[Count][1] = Temp;
                }
                if( Wolf[Count][0] * 10 + Wolf[Count][1] <  Wolf[Min][0] *10 + Wolf[Min][1] )//保存最小序列解
                    Min=Count;
                Count++;
            }
        }
    if( Count == 0)
        printf("No Solution");
    else
        printf("%d %d",Wolf[Min][0],Wolf[Min][1]);
    return 0;
}

你可能感兴趣的:(PAT,B)