汕頭市選2014 分叉___dfs+樹上dp
題目大意:
給出一棵N 個點的樹,點的編號是1, 2,。。。,N。
對於3 個點{a,b,c},如果不存在一條簡單路徑同時經過a,b,c,那麼{a,b,c}是一個分叉。
統計不同分叉的數量。
樹 無環,連通的無向圖
簡單路徑 不重複經過同一個點的路徑
• 對於30% 的資料,N <= 100;
• 對於50% 的資料,N <= 1000;
• 對於100% 的資料,1 <= N <= 10^5。
題解:
這題很神奇,我的程式炸棧了但卻AC了~
這題要建樹,對於他給你的邊,都建雙向邊,然後任選一點構建一顆樹,多餘的邊只需要判斷不要重複走即可。
然後我們假設陣列tree做dp:
當{a,b,c}不是一個分叉時:
Tree[i,1]表示節點i為{a,b,c}的b時候的它的子樹存在多少種解
Tree[i,2]表示以節點i為根節點的子樹有多少個點
Tree[i,3]表示這顆子樹在i固定為b時存在多少個{a,b}
設J為i的兒子:
不難推出:
tree[i,1]=【∑tree[j,2]*(tree[i,2]-tree[j,2])】/2
tree[i,2]=Σtree[j,2]+1
tree[i,3]=tree[i,2]-1
例如這顆樹為:
3
/ \
4 5
那麼
tree[i,1]=(1*1+1*1)/2=1 (有一組{a,b,c}為【4,3,5】)
tree[i,2]=(1+1)+1=3 (有節點【4,5,3】)
tree[i,3]=3-1=2 (有2組以i為b的{a,b}分別為【4,3】,【5,3】)
答案很顯然就是:
N個數內選3個數的情況,設為s,組合數求解:時間複雜度:O(3N)
然後減去成立的{a,b,c}的個數t
t顯然可以推出等於Σ(tree[i,1]+tree[i,3]*(n-tree[i,2]))
為s-t
樹可以用dfs建立,時間複雜度:O(N)
莫名炸棧,題庫AC,恐怖
程式碼:
var
next,list,s,t:array [0..200001] of longint;
tree:array [0..100001,1..3] of int64;
check:Array [0..100001] of longint;
v:array [0..100001] of boolean;
f:array [0..100001,-5..3] of int64;
now,o,i,j,n,m,p,op,kp:longint;
procedure dfs(dep:longint);
var
i,j,k:longint;
begin
check[dep]:=now;
i:=list[dep];
tree[dep,1 ]:=0;
tree[dep,2]:=0;
tree[dep,3]:=0;
j:=0;
k:=0;
while i>0 do
begin
if check[t[i]]=0 then
begin
inc(now);
dfs(t[i]);
j:=j+tree[t[i],2];
tree[dep,2]:=tree[dep,2]+tree[t[i],2];
tree[dep,3 ]:=tree[dep,3]+tree[t[i],2];
inc(k);
end;
i:=next[i];
end;
if k=0 then
begin
tree[dep,2]:=1;
exit;
end;
tree[dep,2]:=tree[dep,2]+1;
i:=list[dep];
while i>0 do
begin
if check[t[i]]>check[dep] then
tree[dep,1]:=tree[dep,1]+tree[t[i],2]*(j-tree[t[i],2]);
i:=next[i];
end;
tree[dep,1]:=tree[dep,1] div 2;
end;
begin
assign(input,'fork.in'); reset(input);
assign(output,'fork.out'); rewrite(output);
readln(n);
f[0,0]:=1;
for i:=1 to n do
for j:=0 to 3 do
f[i,j]:=f[i-1,j]+f[i-1,j-1];
p:=0;
for i:=1 to n-1 do
begin
inc(p);
readln(s[p],t[p]);
next[p]:=list[s[p]];
list[s[p]]:=p;
inc(p);
s[p]:=t[p-1];
t[p]:=s[p-1];
next[p]:=list[s[p]];
list[s[p]]:=p;
end;
now:=1;
dfs(1);
for i:=1 to n do
f[n,3]:=f[n,3]-tree[i,1]-tree[i,3]*(n-tree[i,2]);
writeln(f[n,3]);
close(input); close(output);
end.