noip2003侦探推理详解

耗费了我三个多小时才想明白,orz orz orz

这题就是个坑←_←,这数据就是个逗比→_→ 

题目要求各位自寻,我不想再看见这道题第二遍=A=(数据我就珍藏了=。=)

读入的处理完全是noip提高组的难度,这里P党感觉敲过去就好=。=

对于数据的吐槽我就不写了,因为根本吐槽不完,出数据的简直就是认(sang)真(xin)负(bing)责(kuang),

网上有一个吐槽:http://www.2cto.com/kf/201409/332291.html

数据在最下面,亮点自寻=w=,欢迎花式吐槽=w=


然而最尴尬的就是判断和记录

用suspect[i,j]记录i对j是不是凶手的判断:

suspect[i,j]=1时,i认为j是凶手;

suspect[i,j]=-1时,i认为j不是凶手;


peo[i]记录第i个人的名字

用a[i].day记录第i个人认为今天是星期几


然后咱枚举犯人(guilty)和星期几(today)来对每个人逐一判断(不会傻到用组合去判断谁说假话吧0.0):

咱们用f数组记录我们对第i个人的判断

如果f[i]=1说明他说真话,f[i]=2说明他说假话(注意清0)


由于全部人分为三类:只说真话,只说假话,说废话

所以如果有人既说过真话又说过假话这种情况是不会存在的,直接判断出false就行


然后分类讨论:

1、suspect[i,guilty]=1

说明i说真话,如果f[i]=2即对于这组guilty、today他说过假话,矛盾,返回false 不然的话他说真话f[i]=1

2、suspect[i,guilty]=2

说明i说假话,如果f[i]=1即他说过真话,矛盾返回false,不然f[i]=2

3、对于i对除了guilty以外所有人(j<>guilty)的判断

(1)如果suspect[i,j]=1 说明他认为j是凶手,是假话,如果f[i]=1即他说过真话,矛盾返回false,不然f[i]=2

(2)如果suspect[i,j]=-1说明他认为j不是凶手,是真话,如果f[i]=2即他说过假话,矛盾返回false 不然的f[i]=1

4、a[i].day>0即他说过今天是星期几并且a[i].j<>today 即他说错了,是假话,如果f[i]=1即他说过真话,矛盾返回false,不然f[i]=2

判断完毕=w=


然后我们统计f[i]=2即说谎的人数t1和f[i]=0即不确定的人数t2

然后关键来了

究竟什么是满足要求的情况呢?

t1不一定非要严格等于说谎人数m,

因为有人不确定,

而这批不确定的人中可能也有人是说谎者只是他没说有用的而已(这里一开始没想到跪了3个小时QAQ)

【我走的最长的路就是你的套路】

所以满足的条件是 (t1<=m)and  (t1+t2>=m)


由于结果有三种情况:

1、真相只有一个——有且只有1个满足条件的犯人,直接输出名字

2、他们同伙作案——有大于1个人满足他是犯人的条件,输出Cannot Determine

3、错误的嫌疑人——没有人满足犯人的条件,输出 Impossible 


所以我们如果判断出一个人是犯人不要着急输出,

而是记录我们找到的满足犯人条件的人数t,以及他的名字ans,

每找到一个就t+1,ans更新为他的名字


一个小细节就是我们是犯人和星期同时枚举的,

所以如果我们判断出一个人是犯人就可以直接去判断下一个人不然这一个人会加好几遍


还有判断的时候是区分大小写的

第一组数据中叫GUILTY的那个人说:I am GUILTY 真的是句废话,他就是说他叫GUILTY(=。=)

AC代码:

type
        rec=record
            day:longint;
end;

const
        talk:array[1..5] of string=('I am guilty.','is guilty','Today is','am not guilty','is not guilty');
        d:array[1..7] of string=('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday');
var
        n,m,p,t,tt      :longint;
        ans             :string;
        s,nm            :ansistring;
        b               :boolean;
        a               :array[0..25] of rec;
        f               :array[0..25] of longint;
        i,j,k,l         :longint;
        peo             :array[0..25] of ansistring;
        flag            :array[0..25] of boolean;
        suspect         :array[0..25,0..25] of integer;
function check(guilty,today:longint):boolean;
var
        i,j:longint;
        t1,t2:longint;
begin
   fillchar(f,sizeof(f),0);
   t1:=0;t2:=0;
   for i:=1 to n do
   begin
      if (suspect[i,guilty]=1) then
      begin
         if f[i]=2 then exit(false);
         f[i]:=1;
      end else
      if (suspect[i,guilty]=-1) then
      begin
         if f[i]=1 then exit(false);
         f[i]:=2;
      end;
      //
      for j:=1 to n do
       if (j<>guilty) then
       begin
          if suspect[i,j]=1 then
          begin
             if f[i]=1 then exit(false);
             f[i]:=2;
          end else
          if suspect[i,j]=-1 then
          begin
             if f[i]=2 then exit(false);
             f[i]:=1;
          end;
       end;
       //
       if (a[i].day=today) then
       begin
          if f[i]=2 then exit(false);
          f[i]:=1;
       end else
       if (a[i].day>0) then
       begin
          if f[i]=1 then exit(false);
          f[i]:=2;
       end;
   end;
   //
   for i:=1 to n do
    if (f[i]=2) then inc(t1) else if (f[i]=0) then inc(t2);
   if (t1<=m) and (t1+t2>=m) then exit(true) else exit(false);
end;

begin
   readln(n,m,p);
   for i:=1 to n do readln(peo[i]);
   //
   for i:=1 to p do
   begin
      readln(s);b:=false;
      k:=1;
      //
      nm:=copy(s,1,pos(':',s)-1);
      while (nm<>peo[k]) do inc(k);
      delete(s,1,pos(' ',s));
      //
      for j:=1 to 5 do
       if (pos(talk[j],s)<>0) then
       begin
          b:=true;break;
       end;
     if b then
     begin
        if (j=1) then suspect[k,k]:=1 else
         if (j=2) then
         begin
            nm:=copy(s,1,pos(' ',s)-1);
            l:=1;
            while (peo[l]<>nm) do inc(l);
             suspect[k,l]:=1;
         end else
          if (j=3) then
          begin
             for l:=1 to 7 do if (pos(d[l],s)<>0) then break;
             a[k].day:=l;
          end  else
           if (j=4) then suspect[k,k]:=-1 else
            if (j=5) then
            begin
               nm:=copy(s,1,pos(' ',s)-1);
               l:=1;
               while (peo[l]<>nm) do inc(l);
               suspect[k,l]:=-1;
            end;
     end;
   end;
   //
   t:=0;
   for i:=1 to n do
   begin
    for j:=1 to 7 do
     if check(i,j) then
     begin
        inc(t);ans:=peo[i];break;
     end;
   end;
   //
   if (t=1) then writeln(ans) else
    if (t>1) then writeln('Cannot Determine') else
     writeln('Impossible');
end.

数据:

数据零:

2 2 4
HELLO
GUILTY
HELLO: What is your name?
GUILTY: I am GUILTY.
GUILTY: Are you guilty?
HELLO: I am not guilty.


数据一:

1 0 2
A
A: I am guilty.
A: I am not guilty.
数据二:

5 1 5
A
B
C
D
E
A: Today is Monday.
B: Today is Thursday.
C: Today is Monday.
B: D is not guilty.
E: I am not guilty.
数据三:

7 3 10
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
SUNDAY
MONDAY: Today is Monday.
TUESDAY: Today is Tuesday.
WEDNESDAY: Today is Wednesday.
THURSDAY: Today is Thursday.
FRIDAY: MONDAY is not guilty.
FRIDAY: TUESDAY is not guilty.
FRIDAY: WEDNESDAY is not guilty.
FRIDAY: THURSDAY is not guilty.
SATURDAY: SUNDAY is not guilty.
SUNDAY: SATURDAY is not guilty.
数据四:

4 1 5
KYO
IORI
CHIZURU
OROCHI
KYO: I am guilty.
IORI: I am not guilty.
CHIZURU: OROCHI is guilty.
OROCHI: Today is Monday.
OROCHI: I am guilty.
数据五:

10 7 20
A
AA
AAA
AAAA
AAAAA
AAAAAA
AAAAAAA
AAAAAAAA
AAAAAAAAA
AAAAAAAAAA
A: Today is Monday.
AA: Today is Monday.
AAA: Today is Monday.
AAAA: Today is Monday.
AAAAA: Today is Monday.
AAAAAA: Today is Monday.
AAAAAAA: Today is Monday.
AAAAAAAA: Today is Sunday.
AAAAAAAAA: Today is Sunday.
AAAAAAAAAA: Today is Sunday.
AAAAAAAAAA: AAA is not guilty.
AAAAAAAAA: A is not guilty.
AAAAAAAA: AAAAA is not guilty.
AAAAAAA: AAAAAA is guilty.
AAAAAA: AAAAAAAAAA is guilty.
AAAAA: AAAAAAAA is guilty.
AAAA: AAAAAAA is guilty.
AAA: AA is guilty.
AA: AAAAAAAAA is guilty.
A: AAAAA is guilty.
数据六:

1 1 2
ALAN
ALAN: I am not guity.
ALAN: I am not not guity.
数据七:

3 3 3
SAM
SANDY
SUE
SAM: I am not guity. Am I???
SUE: SANDY is guity.
SANDY: SUE is guity.
数据八:

10 10 10
A
B
C
D
E
F
G
H
I
J
A: B is guilty.
B: C is guilty.
C: D is guilty.
D: E is guilty.
E: F is guilty.
F: G is guilty.
G: H is guilty.
H: I love you!
I: I am not guilty.
J: I is not guilty.
数据九:

1 0 3
CENGJINGYOUYIDUANZHENZHIDEGANQINGFANGZAIWOMIANQIANWOMEIYOUZHENXIDENGDAOSHIQULEYIHOUCAIZHUIHUIMOJIRENSHIJIANZUITONGKUDESHIMOGUOYUCIRUGUOSHANGTIANNENGGEIWOYIGEZAILAIYICIDEJIHUIWOHUIDUINAGENVHAIZISHUOSANGEZI
CENGJINGYOUYIDUANZHENZHIDEGANQINGFANGZAIWOMIANQIANWOMEIYOUZHENXIDENGDAOSHIQULEYIHOUCAIZHUIHUIMOJIRENSHIJIANZUITONGKUDESHIMOGUOYUCIRUGUOSHANGTIANNENGGEIWOYIGEZAILAIYICIDEJIHUIWOHUIDUINAGENVHAIZISHUOSANGEZI: I love you!
CENGJINGYOUYIDUANZHENZHIDEGANQINGFANGZAIWOMIANQIANWOMEIYOUZHENXIDENGDAOSHIQULEYIHOUCAIZHUIHUIMOJIRENSHIJIANZUITONGKUDESHIMOGUOYUCIRUGUOSHANGTIANNENGGEIWOYIGEZAILAIYICIDEJIHUIWOHUIDUINAGENVHAIZISHUOSANGEZI: If there must be a deadline,
CENGJINGYOUYIDUANZHENZHIDEGANQINGFANGZAIWOMIANQIANWOMEIYOUZHENXIDENGDAOSHIQULEYIHOUCAIZHUIHUIMOJIRENSHIJIANZUITONGKUDESHIMOGUOYUCIRUGUOSHANGTIANNENGGEIWOYIGEZAILAIYICIDEJIHUIWOHUIDUINAGENVHAIZISHUOSANGEZI: I hope it is 10000 years!!!


最后这组数据够我笑一年\(^o^)

——by Eirlys

转载请注明出处=w=


  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值