• 【洛谷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;
    	 }
    }
    
  • 相关阅读:
    uva 10491 Cows and Cars
    uva 10910 Marks Distribution
    uva 11029 Leading and Trailing
    手算整数的平方根
    uva 10375 Choose and divide
    uva 10056 What is the Probability?
    uva 11027 Palindromic Permutation
    uva 10023 Square root
    Ural(Timus) 1081. Binary Lexicographic Sequence
    扩展欧几里得(求解线性方程)
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998676.html
Copyright © 2020-2023  润新知