1. 程式人生 > >noip2003偵探推理詳解

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=