• 解题报告:luogu P2014


    题目链接:P2014 选课
    简单的树形(dp),借助(dfs)实现。
    一般的树形(dp)数组是需要二维的,其中一维记录节点(编号或父/子节点的状态(有时三维)),另一维记录权值或计数。
    重要的是判断从根节点(dp)还是从叶节点(dp),显然此题需从叶节点开始。
    我们记(dp[i][j])为从(i)节点向下选(j)个节点最大权值(注意不包括自己),易得方程:

    [dp[i][j]=max(dp[i][j],dp[i][j-k-1]+dp[i_{son}][k] ]

    注意减一,因为不算他自己。
    注意(j)要逆序扫,避免重选点,可以在回溯中直接实现,一个(dfs)即可,复杂度挺玄学的,大概是(O(n^3))量级的,可以通过此题。
    重要的是我两小时没刚出来啊,我绝对的不会(dp)
    贴下代码:

    (Code):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    struct node
    {
    	int to,nxt;
    }e[305];
    int head[305],cnt=0;
    void add(int u,int v)
    {
    	e[++cnt].to=v;
    	e[cnt].nxt=head[u];
    	head[u]=cnt;
    }
    int son[305],dp[305][305];
    int n,m,fa;
    int dfs(int cur)
    {
    	int son=1;
    	for(int i=head[cur];i;i=e[i].nxt)
    	{
    		int v=e[i].to;
    		int sontree=dfs(v);
    		son+=sontree;
    		for(int j=son;j>=0;j--)//倒着扫,想想为什么,我上面说了
    		{
    			for(int k=0;j-k-1>=0&&k<sontree;k++)//注意边界条件 
    			{
    				dp[cur][j]=max(dp[cur][j],dp[cur][j-k-1]+dp[v][k]);
    			}
    		}
    	}
    	return son;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&fa,&dp[i][0]);
    		add(fa,i);
    	}	
    	dfs(0);
    	printf("%d
    ",dp[0][m]);
    	return 0;
    }
    

    然后就这样(A)了。

  • 相关阅读:
    crystal report 用存储过程的问题。
    新的开始—2014
    C#基础(二)——C#中的构造函数
    C#基础(一)——C#中反斜杠/n与/r的区别
    Html基础(一)
    yield关键字, default关键字, 别名关键字
    让 wpf tabcontrol 延缓初始化每个tab item content
    MVC,MVP,MVVM(补充)
    Focus scope in WPF
    Wpf ItemsControl 开启UI Virtualization 的条件
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12303112.html
Copyright © 2020-2023  润新知