第三题:T3树的连通子图
标签:树、树形 d p dp dp
题意:给定一棵 n n n个结点的树, 1 1 1号点为这棵树的根。计算这棵树连通子图的个数,答案对 1 , 000 , 000 , 007 1,000,000,007 1,000,000,007取余数。
题解:经典树形 d p dp dp,对于每个节点 u u u分两种情况:
dp[u][0]:表示含有以u节点作为根的连通子图个数
dp[u][1]:表示不含有以u节点作为根的连通子图个数
- 对于节点 u u u的每个孩子节点 v v v来说,如果把 u u u算上去,连通子图的个数要做乘积(乘法原理)
- 对于节点 u u u的每个孩子节点 v v v来说,如果不把 u u u算上去,连通子图的个数要做相加(加法原理)
可以结合样例和给出的图,自己再推一推,想一想。做法是先把图存进邻接表里面,既然是根节点为 1 1 1,并且给出的都是每个节点的父亲节点,直接存单向边,然后从根节点 1 1 1从上往下遍历树,对应更新 d p [ u ] [ 0 ] dp[u][0] dp[u][0]和 d p [ u ] [ 1 ] dp[u][1] dp[u][1]即可。
代码:
#include <bits/stdc++.h>
using namespace std;typedef long long ll;
const ll mod = 1e9 + 7;
vector<ll> e[200005];
ll dp[200005][2];
// dp[u][0]: 含有以u节点作为根的连通子图个数
// dp[u][1]: 不含有以u节点作为根的连通子图个数void dfs(ll u) {dp[u][0] = 1;for (int i = 0; i < e[u].size(); i++) {ll v = e[u][i];dfs(v);dp[u][0] = (dp[u][0] * (dp[v][0] + 1)) % mod;dp[u][1] = (dp[u][1] + dp[v][0] + dp[v][1]) % mod;}
}int main() {ll n, x;cin >> n;for (int i = 2; i <= n; i++) {cin >> x;e[x].push_back(i);}dfs(1);cout << (dp[1][0] + dp[1][1]) % mod << endl;return 0;
}