題意是求一棵無根樹本質不同獨立集的個數
那個所謂「極寒點」的選取就是獨立集。
結構相同就是樹同構,完全相同就是樹的形態和獨立集都相同。
我們先求出樹的重心,就可以轉化為有根樹同構問題。
令$f[u][1]$為在$u$的子樹中,選取$u$的方案樹,$f[u][0]$為在$u$的子樹中,不選取$u$的方案數。
得到最基本的dp方程:
$f[u][0]=\prod_(f[v][0]+f[v][1])$
$f[u][1]=\prod_f[v][0]$
但是可能出現直徑長為奇數的情況,需要分類討論。
判斷樹同構用雜湊亂搞就好了。
1 #include 2 #include 3 #includebzoj 31624 #include 5
using
namespace
std;
6#define maxn 500010
7#define mod 1000000007
8#define p1 2150527
9#define p2 1231231237
10#define ll long long
11 inline int
read()
1221
while(ch>='
0'&&ch<='9'
)22 s=s*10+ch-'
0',ch=getchar();
23return s*f;24}
25struct
edge
26e[maxn<<1
];29
int pr[maxn],cnt=1;30
intsiz[maxn];
31void add(int u,int
v)32
;34 pr[u]=cnt;
35 e[++cnt]=(edge);
36 pr[v]=cnt;37}
38int rt[2
],root;
39ll inv[maxn];
40ll haha[maxn];
41 ll f[maxn][2
];42
intst[maxn];
43bool cmp(int a,int
b)44
47 ll c(int n,int
m)48
54void dp(int u,int
fa)55
74for(i=1;i<=top;i++)
75 haha[u]=haha[u]*p1+(haha[st[i]]+i)*p2;76}
77int
n;78
void dfs(int u,int
fa)7993}
94if((siz[u]<<1)
95 flag=0;96
if(flag)
97103
}104
void
init()
105110
intmain()
111121 dfs(1,0
);122
if(rt[1
])123
131 add(root,rt[0
]);132 add(root,rt[1
]);133
}134
else
135 root=rt[0
];136 dp(root,0
);137
if(!rt[1
])138 printf("
%lld
",(f[root][0]+f[root][1])%mod);
139else
140148 }
BZOJ3162 獨釣寒江雪
bzoj 你要給乙個樹上的每個點黑白染色,要求白點不相鄰。求本質不同的染色方案數。兩種染色方案本質相同當且僅當對樹重新標號後對應節點的顏色相同。n le 5 times10 5 首先考慮沒有本質相同那個限制怎麼做。直接設 f 表示 i 點染成黑色 白色時子樹內的方案數。轉移很簡單 f prod j ...
BZOJ3162 獨釣寒江雪 樹同構 DP
題解 先進行樹hash,方法是找重心,如果重心有兩個,則新建乙個虛點將兩個重心連起來,新點即為新樹的重心。將重心當做根進行hash,hash函式不能太簡單,我的方法是 將x的所有兒子的hash值排序,然後將這些hash值立方合在一起作為x的hash值。進行完樹hash後,我們考慮dp。首先不考慮同構...
BZOJ3162 獨釣寒江雪(雜湊 樹形dp)
數獨立集顯然是可以樹形dp的,問題在於本質不同。假設已經給樹確立了乙個根並且找到了所有等效 注意是等效而不是同構 子樹,那麼對轉移稍加修改使用隔板法就行了。關鍵在於找等效子樹。首先將樹的重心 若有兩個則加乙個點作為唯一重心 作為根。這樣任意極大等效子樹 比如某兩個等效子樹裡面的一部分等效,那麼裡面這...