題意
有三類動物a,b,c,題中給出兩種關係:
1 x y :x y 同類
2 x y :x吃y
對於假話的定義:
1.當前的話與前面的某些真的話衝突,就是假話;
2.當前的話中x或y比n大,就是假話;
3.當前的話表示x吃x,就是假話。
現在給出n句這樣的關係,求假話個數。
分析這是第二次寫這道題了,第一次是去年剛學並查集的時候。當初囫圇吞棗a了,現在拿出來發現自己根本就沒明白。
感覺,經典的題還是要時常拿出來做一做。
剛才某人吐槽:這題比就我小4歲。呵呵....
廢話少說,說正題。
看題解寫的,這個人的分析很詳細哦~!膜拜!
感覺他說的太詳細了,所以鄙人就摘抄並整理修改一下這位大神的,自己也沒什麼可寫的了...謝謝大神
part i - 權值(relation)的確定。
我們根據題意,森林中有3種動物。a吃b,b吃c,c吃a。
我們還要使用並查集,那麼,我們就以動物之間的關係來作為並查集每個節點的權值。
注意,我們不知道所給的動物(題目說了,輸入只給編號)所屬的種類。
所以,我們可以用動物之間「相對」的關係來確定乙個並查集。
0 - 這個節點與它的父節點是同類
1 - 這個節點被它的父節點吃
2 - 這個節點吃它的父節點。
注意,這個0,1,2所代表的意義不是隨便制定的,我們看題目中的要求。
說話的時候,第乙個數字(下文中,設為d)指定了後面兩種動物的關係:
1 - x與y同類
2 - x吃y
我們注意到,當 d = 1的時候,( d - 1 ) = 0,也就是我們制定的意義
當 d = 2的時候,( d - 1 ) = 1,代表y被x吃,也是我們指定的意義。
所以,這個0,1,2不是隨便選的
part ii - 路徑壓縮,以及節點間關係確定
確定了權值之後,我們要確定有關的操作。
我們把所有的動物全初始化 relation[i]=0,f[i]=i
(1)路徑壓縮時的節點演算法
通過窮舉我們可以發現
f[now]=f[f[now]]
relation[now]=(relation[now]+relation[f[now]]) % 3
這個路徑壓縮演算法是正確的
關於這個路徑壓縮演算法,還有一點需要注意的地方,我們一會再談
注意,根據當前節點的relation和當前節點父節點的relation推出
當前節點與其父節點的父節點的relation這個公式十分重要!!
它推不出來下面都理解不了!!自己用窮舉法推一下:
好吧,為了方便伸手黨,我給出窮舉過程
i j
爺爺 父親 兒子 兒子與爺爺
0 0 (i + j)%3 = 0
0 1 (i + j)%3 = 1
0 2 (i + j)%3 = 2
1 0 (i + j)%3 = 1
1 1 (i + j)%3 = 2
1 2 (i + j)%3 = 0
2 0 (i + j)%3 = 2
2 1 (i + j)%3 = 0
2 2 (i + j)%3 = 1
嗯,這樣可以看到,( 兒子relation + 父親relation ) % 3 = 兒子對爺爺的relation
所以有relation[now]=(relation[now]+relation[f[now]]) % 3
這就是路徑壓縮的節點演算法
(2) 集合間關係的確定
relation[find(y)]=(3-relation[y]+(d-1)+relation[x]) % 3;
這個公式,是分三部分,這麼推出來的:
( d - 1 ) :這是x和y之間的relation,x是y的父節點時,y的relation就是這個
3 - relation[y] = 根據y與根節點的關係,逆推根節點與y的關係
這部分也是窮舉法推出來的,我們舉例:
0(父子同類)( 3 - 0 ) % 3 = 0
1(父吃子) ( 3 - 1 ) % 3 = 2 //父吃子
2(子吃父) ( 3 - 2 ) % 3 = 1 //子吃父,一樣的哦親
所以有y的父結點與x的父結點關係relation[find(y)]=(3-relation[y]+(d-1)+relation[x]) % 3;
注意,這個當所有集合都是初始化狀態的時候也適用
part iii - 判斷
先處理特殊情況:
1.當x>n或y>n時,為假話(在這裡竟然wa了一次...囧還是太不認真了)
2.當d=2而x=y時,為假話
其實所有的不同集合到最後都會被合併成乙個集合的。我們只要在乙個集合中找那些假話就可以了。
(1)首先,如何判斷
1 x y是不是假話。//此時 d = 1
if ( x 和 y 不在同一集合) union(x,y,xroot,yroot,d)
else if x.relation != y.relation ->假話
(2)其次,如何判斷
2 x y是不是假話 //此時d = 2
if ( x 和 y 不在同一集合)union(x,y,xroot,yroot,d)
else (relation [y]+ 3 - relation[x] ) % 3 != 1 ->假話
這個公式是這麼來的:
3 - relation[x]得到了根節點關於x的relation,
relation [y]+ 3 - relation[x]得到了y關於x的relation
所以,只要y關於x的relation不是1,就是y不被x吃的話,這句話肯定是假話!
綜合(1) 和(2),無論d=1或2,只要滿足 ((relation[y]-relation[x]+3) mod 3)<>(d-1)
即為假話
accepted code
167program poj1182;
8const
9 infile = '
poj1182.in';
10 outfile = '
poj1182.out';
11var
12 relation,f:array[0..50030
]of longint;
13n,k,d,x,y,ans,i,fx,fy:longint;
14function find(x:longint):longint;
15var
16fx:longint;
17begin
18 if f[x]=x then exit(x)
19else begin
20 fx:=find(f[x]);
21 relation[x]:=(relation[x]+relation[f[x]]) mod 3
;22 f[x]:=fx;
23exit(fx);
24end;
25end;
26procedure union(x,y,fx,fy,d:longint);
27begin
28 f[fy]:=fx;
29 relation[fy]:=(3-relation[y]+d-1+relation[x]) mod 3;30
end;
31begin
32assign(input,infile);reset(input);
33assign(output,outfile);rewrite(output);
34readln(n,k);
35 for i:=1
to n do begin
36 f[i]:=i;
37 relation[i]:=0;38
end;
39 for i:=1
to k do begin
40readln(d,x,y);
41 if (x>n) or (y>n) then begin
42inc(ans);
43continue;
44end;
45 if (d=2) and (x=y) then begin
46inc(ans);
47continue;
48end;
49 fx:=find(x);fy:=find(y);
50 if fx<>fy then union(x,y,fx,fy,d);
51else begin
52 if (((relation[y]-relation[x]+3) mod 3)<>(d-1
)) then inc(ans)
53end;
54end;
55writeln(ans);
56close(input);close(output)
57end.
58
poj 1182 帶權並查集
description 動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a吃b,b吃c,c吃a。現有n個動物,以1 n編號。每個動物都是a,b,c中的一種,但是我們並不知道它到底是哪一種。有人用兩種說法對這n個動物所構成的食物鏈關係進行描述 第一種說法是 1 x y 表示x和y是...
poj1182 帶權並查集
題意 中文題就不描述了 思路 帶權並查集模板題 加入乙個陣列 表示這個點和它父節點的關係 表示同類,表示父親吃它,表示它吃父親 每次需要更新和父親之間的關係 include includeconst int n 50005 int p n r n n,k void init int x int fi...
POJ 1182 帶權並查集
食物鏈 time limit 1000ms memory limit 10000k total submissions 89563 accepted 26905 description 動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a吃b,b吃c,c吃a。現有n個動物,以1 n...