【题解】[HNOI2015] 落忆枫音
感觉这题挺有意思的,遂写。
题目大意
给出一个有向无环图,再给定两个点 \(s\) 和 \(t\),表示在点 \(s\) 和 \(t\) 间加上一条边。求这个图有多少种生成树。
题目分析
首先考虑不加边之前的情况,假设给定下面这个图:
根据树的定义,除根节点外的节点有且只有一个父亲节点,也就是说对于每一个节点,我们要指定一个唯一的父节点。比如上图的点 \(5\),它在生成树上的父节点可以是 \(2\) 或者 \(6\)。又因为每个节点取父节点的情况互不干扰且是个无环图,所以用乘法原理可得生成树的方案有 \(\prod\limits_{i=2}^n in[i]\)。\(in[i]\) 表示点 \(i\) 的入度,也就是有 \(in[i]\) 个父节点可能。
再考虑加上一条边后可能有环的情况。将上图添加一个由 \(6\) 到 \(2\) 的有向边。
此时,点 \(2\),\(4\),\(6\) 形成一个环。我们发现,即使现在点 \(in[2]=2\),但它的合法方案只有 \(1\),因为它的父节点不能为点 \(6\),否则会形成环,不符合树的定义。
所以最后的方案数就等于所有方案数减去成环的方案数,而要使一个可以成环的点集成环,它有且只有一种方案,即每个节点的父节点都是上一个环上的点。如上图,若 \(6\) 的父节点是 \(4\),\(4\) 的父节点是 \(2\),但 \(2\) 的父节点是 \(1\) 的话,这时候不会形成一个环。
令集合 \(S\) 包含所有在环内的点,得出最后的结论:\(ans=\prod\limits_{i=2}^n in[i]-\prod\limits_{i\notin S,i\neq1}in[i]\)
我们令 \(dp[i]\) 表示从 \(t\) 到 \(i\) 的含环数量,用拓扑排序维护转移。初始值 \(dp[t]=\prod\limits_{i=2}^n in[i]\),状态转移 \(dp[v]=\frac{dp[u]}{in[v]}\)(\(u\) 可达 \(v\))。可以这样理解这个状态转移,由于多了一条 \((s,t)\) 的边,所以所有从 \(t\) 到 \(s\) 的路径上的点必然处于一个这条路径加上 \((s,t)\) 所形成的环上,每次转移一次就相当于除上一个在环上的 \(in[i]\) 值,最后的 \(dp[s]\) 就是所有有环的方案数。
最后注意由于 \(s\) 到 \(t\) 多加了一条边,所以 \(in[t]\) 要加一。但拓扑排序时 \(in[t]\) 要减回来,否则不一定能遍历到它在环上。
总结
遇到在一个较简单的基础上增添一些性质的题,可以从简单的基础上出发,最后再减去不合法方案。