Codeforces Round #630 (Div. 2) F. Independent Set (树型dp)

https://codeforces.com/contest/1332/problem/F

 

题中描述是一棵树,给出树上子图存在独立点集的定义:G‘为全图G的子图,G‘在存在点对(u,v),E(u,v)不存在。现求G中有多少个子图可以满足存在独立点集?求所有的方案数。

 

题目抽象为:在树中的子树中选出一些点,它们互相之间不存在直接的连边,求这样的点集方案数。考虑树型dp做法。设计状态dp[u][0]表示当前结点u不作为独立点的方案数,dp[u][1]表示当前结点u作为独立点的方案数。

假设不考虑子图,那么dp[u][0] = ∏ dp[v][0] + dp[v][1],dp[u][1] = ∏ dp[v][0],这是一个很显然的树型dp转移方程,其中v是u的儿子结点。

由于题中说明是求子图的方案数,那么还需要考虑u和v不连边的情况了。当u和v不连边去构成独立子图时,任何的结点x不能单独作为孤立的独立点存在,也就是说x如果作为独立点,不和任何结点连边是不合法的。再设计状态f[u]为u结点作为孤立点集存在的方案数,f[u]显然是从儿子结点v转移而来,f[u] = ∏ dp[v][0] + dp[v][1] - f[v] 。为什么转移方程要减去f[v]?是因为结点v作为独立点出现时,不能单独存在,所以要令dp[v][1] - f[v]。

那么新的转移方程就是 :

dp[u][0] = ∏ dp[v][0] + dp[v][1] + dp[v][0] + dp[v][1] - f[v]  (需要考虑u和v不连边的情况)

dp[u][1] = ∏ dp[v][0] + dp[v][0] + dp[v][1] - f[v]  (同样需要考虑u和v不连边的情况,此时v可以是独立点)

f[u] = ∏ dp[v][0] + dp[v][1] - f[v]

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 3e5+5;
 5 const ll mod = 998244353;
 6 vector<int> g[maxn];
 7 ll dp[maxn][3],f[maxn];
 8 void dfs(int cur,int fa){
 9     dp[cur][0] = dp[cur][1] = f[cur] = 1;
10     for(int i = 0;i<g[cur].size();i++){
11         int v = g[cur][i];
12         if(v == fa) continue;
13         dfs(v,cur);
14         dp[cur][0] = dp[cur][0] * ((2 * dp[v][0] + 2 * dp[v][1] - f[v])%mod) % mod;
15         dp[cur][1] = dp[cur][1] * ((2 * dp[v][0] + dp[v][1] - f[v]) % mod) % mod;
16         f[cur] = f[cur] * ((dp[v][0] + dp[v][1] - f[v]) % mod) % mod;
17     }
18 }
19 int main() {
20     int n;
21     scanf("%d",&n);
22     for(int i = 1;i<n;i++){
23         int u,v;
24         scanf("%d%d",&u,&v);
25         g[u].push_back(v);
26         g[v].push_back(u);
27     }
28     dfs(1,0);
29     cout<<(dp[1][0]+dp[1][1]-f[1]-1+3*mod)%mod;
30     return 0;
31 }

 

posted @ 2020-04-08 00:06  AaronChang  阅读(240)  评论(0编辑  收藏  举报