您的位置:首页 > 编程语言 > C语言/C++

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

2019-02-07 11:07 459 查看
版权声明:本文为博主原创文章,欢迎交流学习,未经博主允许不得转载。 https://blog.csdn.net/qq_43749739/article/details/86767821

一、题目

以下文字摘自《灵机一动·好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中,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<M 使得 a[i]=b[i] (i≤k),且 a[k+1]<b[k+1],则称序列 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

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

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

三、思路一代码实现

#include <stdio.h>
#include <stdlib.h>
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是狼看起来好方便(哭)
别问,问就是过年好
哈哈哈哈哈哈哈哈哈过年好!!

要不是数量小我觉得我铁超时…

主要思路:

设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 <stdio.h>
#include <stdlib.h>
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: