题意:给定一棵树,从中选出一些节点,使得不成父子关系的节点对数最多。问这个最大值是多少。
思路:首先既然是给定一颗树,先要选择合适的数据结构,来保存这颗树。由于这颗树只关心根节点在哪里,所以只需要用一个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][]; // dp[i][0] 表示不选择结点 i,dp[i][1] 表示选择结点 i
int father[maxn]; // father 记录了结点的父结点编号 void tree_dp(int node) {
dp[node][] = ;
dp[node][] = ;
for(int i = ; i <= n; i++) {
if(father[i] == node) { // i 为 node 的子结点
tree_dp(i); // 递归计算子结点
// 关键
dp[node][] += dp[i][]; // 选择父结点,则必须不选择子结点
dp[node][] += max(dp[i][], dp[i][]); // 不选择父结点,则可以选择或不选择子结点
}
}
} int main() {
int f, c, root;
scanf("%d", &n);
memset(father, , sizeof(father));
memset(visited, , sizeof(visited));
root = ; // 记录树的根结点
while (scanf("%d %d", &c, &f), c || f) { // 读入父子关系,前一个结点是后一个结点的孩子
father[c] = f;
root = f;
}
while(father[root]) { // 查找根结点
root = father[root];
}
tree_dp(root); // 从根结点出发进行动态规划
printf("%d\n", max(dp[root][], dp[root][])); // 求出最终答案,根可以选或不选
return ;
}