zoukankan      html  css  js  c++  java
  • 解题报告: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)了。

  • 相关阅读:
    将博客搬至CSDN
    Linux-进程管理&网络管理
    MySQL架构备份之双机热备
    Linux目录结构&文件管理
    markdown文件即 .md 的基本常用编写语法
    Nginx
    Java 面试题(收集整理...ing)
    CentOS7 VS CentOS8
    Linux 学习
    vi/vim 命令整理
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12303112.html
Copyright © 2011-2022 走看看