1. 程式人生 > >汕頭市選2014 分叉___dfs+樹上dp

汕頭市選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.