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;
    	 }
    }
    
  • 相关阅读:
    Sprinig.net 双向绑定 Bidirectional data binding and data model management 和 UpdatePanel
    Memcached是什么
    Spring.net 网络示例 codeproject
    jquery.modalbox.show 插件
    UVA 639 Don't Get Rooked
    UVA 539 The Settlers of Catan
    UVA 301 Transportation
    UVA 331 Mapping the Swaps
    UVA 216 Getting in Line
    UVA 10344 23 out of 5
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998675.html
Copyright © 2011-2022 走看看