题意:给定一棵树,从中选出一些节点,使得不成父子关系的节点对数最多。问这个最大值是多少。
思路:首先既然是给定一颗树,先要选择合适的数据结构,来保存这颗树。由于这颗树只关心根节点在哪里,所以只需要用一个fa数组来保存每个点的根节点,此外设初始化为0,所以根节点的fa[root]为0,所以从任意一个结点的父节点往上遍历,直到遍历到某某个结点的父节点为0,则这个结点就是父节点
这道题个人感觉关键是从根节点开始往下dp,所以根节点要确定..
这道题的状态转移方程为,dp[i][1],选用第i个节点时,所能得到的最大对数,dp[i][0]不选用第i个节点时所能得到的最大对数,dp[i][0]=求和max(dp[j][0],dp[j][1]);dp[i][1]=求和dp[j][0].所以每一个父节点都依赖于它的子节点。所以递归求每一个子节点的dp[j]的值,最后在累加到dp[i]上,而边界条件是,递归到叶子节点时,dp[i][0]=0,dp[i][1]=1;加上代码
int n; // 结点个数 int dp[maxn][2]; // dp[i][0] 表示不选择结点 i,dp[i][1] 表示选择结点 i int father[maxn]; // father 记录了结点的父结点编号 void tree_dp(int node) { dp[node][0] = 0; dp[node][1] = 1; for(int i = 1; i <= n; i++) { if(father[i] == node) { // i 为 node 的子结点 tree_dp(i); // 递归计算子结点 // 关键 dp[node][1] += dp[i][0]; // 选择父结点,则必须不选择子结点 dp[node][0] += max(dp[i][1], dp[i][0]); // 不选择父结点,则可以选择或不选择子结点 } } } int main() { int f, c, root; scanf("%d", &n); memset(father, 0, sizeof(father)); memset(visited, 0, sizeof(visited)); root = 0; // 记录树的根结点 while (scanf("%d %d", &c, &f), c || f) { // 读入父子关系,前一个结点是后一个结点的孩子 father[c] = f; root = f; } while(father[root]) { // 查找根结点 root = father[root]; } tree_dp(root); // 从根结点出发进行动态规划 printf("%d ", max(dp[root][0], dp[root][1])); // 求出最终答案,根可以选或不选 return 0; }