zoukankan      html  css  js  c++  java
  • 【洛谷P1352】没有上司的舞会【树形DP】

    题目大意:

    题目链接:https://www.luogu.org/problemnew/show/P1352
    给出一棵带点权的树,若选择一个点,那么不能选择这个点的父节点。求最大点权和。


    思路:

    很经典的一道树形DP题目。当然DFS也应该可以过。
    f[i][0/1]f[i][0/1]表示选择或不选择第ii个结点的最大点权和。那么我们如果选择了这个点,那么它的子节点就不能选择,就有方程:
    f[i][1]=j=1son[i]f[j][0]f[i][1]=\sum^{son[i]}_{j=1}f[j][0]
    那如果不选这个点,那么子节点选或不选都可以,那么:
    f[i][0]=j=1son[i]max(f[j][1],f[j][0])f[i][0]=\sum^{son[i]}_{j=1}max(f[j][1],f[j][0])


    代码:

    #include <cstdio>
    #include <map>
    using namespace std;
    
    int n,x,y,f[6001][2],num[6001],a[6001];
    bool not_root[6001];
    map<pair<int,int>,int> son;
    
    void dp(int x)  //递归
    {
    	f[x][0]=0;
    	f[x][1]=a[x];  //初始化
    	for (int i=1;i<=num[x];i++)  //枚举所有子节点
    	{
    		dp(son[make_pair(x,i)]);  //求子节点的最优答案
    		f[x][0]+=max(f[son[make_pair(x,i)]][0],f[son[make_pair(x,i)]][1]);  //方程1
    		f[x][1]+=f[son[make_pair(x,i)]][0];  //方程2
    	}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    	 scanf("%d",&a[i]);
    	while (scanf("%d%d",&x,&y))
    	{
    		if (!x&&!y) break;
    		son[make_pair(y,++num[y])]=x;
    		not_root[x]=true;  //有父亲就肯定不是根节点
    	}
    	for (int i=1;i<=n;i++)
    	 if (!not_root[i])  //是根节点
    	 {
    	 	dp(i);
    	 	printf("%d\n",max(f[i][0],f[i][1]));
    	 	return 0;
    	 }
    }
    
  • 相关阅读:
    Luogu-P2295 MICE
    Luogu-P2627 修剪草坪
    Loj-10176-最大连续和
    Luogu-P1886 滑动窗口
    Luogu-P3807 【模板】卢卡斯定理
    Luogu-P1879 [USACO06NOV]玉米田Corn Fields
    Luogu-P1896 [SCOI2005]互不侵犯
    Loj-SGU 223-国王
    Luogu-P2657 [SCOI2009]windy数
    素数
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998677.html
Copyright © 2011-2022 走看看