爆刷PAT(甲级)——之【1148】 Werewolf - Simple Version(20 分)——思维

之前考的时候想不到。今日抽空解决一下。

题意:N个人各指认一个人是好人还是坏人。其中有两个坏人,剩下的都是好人。而且必然是一个好人和一个坏人说的是谎话。给出他们互相指认的信息,请判断出哪两个是坏人。如果由多种答案,输出最小标号的组合。

 

难点:当初看到数据量N小于等于200,就知道使用暴力。但是没想到怎么去暴力。

当时吧以为人物之间的指认关系是像一张拓扑图一样,所以某个人说的如果是谎话的话后面的节点(后续的指认)都会反过来,就理所当然的以为是搜索的题目了。但这样子加入暴力枚举那两个人是狼,就没想好怎么去寻找拓扑图的开始节点。

昨天重拾,发现自己想多了。这个题目并不是一个拓扑图。因为如果A说B是好人,B说C是好人。如果A是说了谎,并不会改变B说的话的确信度。我自己坑了我自己,想复杂了。

这个题目中设定了好人和坏人;撒谎的人和没有撒谎的人。这两个概念是独立的,不要混在一起,是考验逻辑呀。

所以解决方案是,枚举两个人是坏人,如此一来坏人的身份已经全部确定,接下来如果有哪个人A说某个人B是坏人,而这个被告B并不是我们枚举的坏人,那么这个A就是在扯淡,就是说谎的人!如果哪个人A说某个人B是好人,但是这个人B分明就是我们已经假定的坏人,那这个A又在扯淡,也是说谎的人!

如此以来,每次枚举两个坏人的情况下,我们可以分别确定出在这种情形下撒谎的人的个数。

题目说,撒谎的只有两人,而且一人是好人一人是坏人。所以我们分别统计各好人和坏人撒谎的人数是否都为1,若是即为答案。

 

Code:

#include<bits/stdc++.h>
using namespace std;
#define inf 209
#define INF 0x3f3f3f3f

int man[inf];//输入指控
int judge(int v,int wolf1,int wolf2)//返回1则在说谎
{
    int u=man[v];
    int pos=abs(u);
    if(u<0&&pos!=wolf1&&pos!=wolf2)return 1;//说别人坏人但是对方是好人
    if(u>0&&(pos==wolf1||pos==wolf2))return 1;//说对方好人但对方是坏人
    return 0;
}
int main()
{
    int i,j,k;
    int n;
    int sum1,sum2;//说谎者:狼-人
    cin>>n;
    for(i=1;i<=n;i++)cin>>man[i];
    for(i=1;i<n;i++)//狼1
        for(j=i+1;j<=n;j++)//狼2
        {
            sum1=sum2=0;
            for(k=1;k<=n;k++)
            {
                sum1+=judge(k,i,j)&&(k==i||k==j);//狼说谎
                sum2+=judge(k,i,j)&&k!=i&&k!=j;//村民说谎
            }
            if(sum1==1&&sum2==1)
            {
                printf("%d %d\n",min(i,j),max(i,j));
                return 0;
            }
        }
    printf("No Solution\n");
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值