FZU-2202-犯罪嫌疑人 -10.1训练赛

PS:我看的别人的博客理解的,比赛的时候没弄出来

PS:转载链接

存在犯罪嫌疑人,当他是实际犯罪者的时候,恰好有且仅有M句话是真话。

那么,如果我们假定一个人是犯罪嫌疑人,有几句话是真话呢?

假设有A句是说xxx是犯罪者的句式,B句是说xxx不是犯罪者的句式。

那么当某人X为犯罪嫌疑人的时候,

真话句数=说X为犯罪者的数量+(B-说X不是犯罪者的数量)//非常自然对吧

然后我们可以得知,哪些人可能是犯罪者了。

如果只有1个人,那么每个人说的话的真假是直接被确定了,毫无疑问。

如果有多个人,

  • 如果某人说的是xxx是犯罪者的句式,如果xxx可能为犯罪者,则他的话可真可假;如果xxx不可能是犯罪者,那他说的一定是假话。
  • 如果某人说的是xxx不是犯罪者的句式,如果xxx可能为犯罪者,则他的话可真可假;如果xxx不可能是犯罪者,那他说的一定是真话。

所以O(n)统计每个人被指认多少次+每个人被排除嫌疑多少次,O(n)来判断每个人是不是可能是犯罪嫌疑人。最后O(n)推断每句话的真假,没了。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <limits.h>
#include <math.h>
using namespace std;
const int maxn = 1e5+10;
int ls[maxn];///记录每个人说的信息
int vis[maxn];///记录人是不是可能为犯罪
int va[maxn], vb[maxn];///va记录说第i个人犯罪的个数,vb是说第i个人没有犯罪的人数
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n, m;
        scanf("%d%d",&n,&m);
        fill(vis,vis+n+1,0);///fill 相当于memeset,但是memsest去清0和-1很好,清其他用fill比较好
        fill(va,va+n+1,0);///memset(va,0,(n+1)*sizeof(int);
        fill(vb,vb+n+1,0);
        int cat = 0, cbt = 0;///cat 是说犯罪的人数,cbt是说没犯罪的人数
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&ls[i]);
            if(ls[i] > 0)
            {
                cat++;
                va[ls[i]]++;
            }
            else
            {
                cbt++;
                vb[-ls[i]]++;
            }
        }
        int ant = 0;
        for(int i = 1; i <= n; i++)
        {
            int tmp = va[i] + (cbt-vb[i]);///说第i个犯罪人的个数加上说其他人没犯罪的人数
            if(tmp == m)///如果恰好等于m的话,说明该人可能犯罪啊
            {
                ant++;
                vis[i] = 1;
            }
        }
        if(ant == 1)///找到一个可能的犯罪的
        {
               for(int  i = 1; i <= n; i++)
               {
                   if(ls[i] > 0)
                   {
                       if(vis[ls[i]])///与该人的说法相同
                       {
                           puts("Truth");
                       }
                       else
                          puts("Lie");
                   }
                   else
                   {
                       if(vis[-ls[i]])///和该人的说法相反
                       {
                           puts("Lie");
                       }
                       else
                       {
                           puts("Truth");
                       }
                   }
               }
        }
        else///多个人可能是犯罪的
        {
            for(int i = 1; i <= n; i++)
            {
                if(ls[i] > 0)
                {
                    if(vis[ls[i]])///该人说他的判断的人犯罪了,没法判断,因为有多个可能的人选
                    {
                        puts("Not defined");
                    }
                    else///可以清楚的知道该人不是可能的犯罪的,他就说谎了
                        puts("Lie");
                }
                else
                {
                    if(vis[-ls[i]])///该人说他的判断的人没有犯罪了,没法判断,因为有多个可能的人选
                    {
                        puts("Not defined");
                    }
                    else///可以清楚的知道该人不是可能的犯罪的,所以该人说的对
                        puts("Truth");
                }
            }
        }
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值