Vijos 1180 (树形DP+背包)

题目链接https://vijos.org/p/1180

题目大意:选课。只有根课选了才能选子课,给定选课数m, 问最大学分多少。

解题思路

树形背包。cost=1。

且有个虚根0,取这个虚根也要cost,所以最后的结果是dp[0][m+1]。

本题是cost=1的特殊背包问题,在两个for循环上有一个优化。

for(f+1...j....cost)

for(1....k...j-cost)

其中f为当前已经dfs子结点个数。之所以+1,是因为根要预留一个空间。

f+=dfs(t),dfs(t)返回的是子点t的f+1。

其实可以直接把f+1写成m+1, 不过要多跑几次循环。

这种写法在POJ 1155中对于子结点不完全取将会起到很大作用。

#include "iostream"
#include "cstdio"
#include "cstring"
using namespace std;
#define maxn 305
int n,m,root,x;
int dp[maxn][maxn],head[maxn],w[maxn],tol;
struct Edge
{
    int to,next;
}e[maxn];
void addedge(int u,int v)
{
    e[tol].to=v;
    e[tol].next=head[u];
    head[u]=tol++;
}
int dfs(int root)
{
    int i=root,f=0,cost=1;
    for(int i=cost;i<=m;i++) dp[root][i]=w[root];
    for(int a=head[root];a!=-1;a=e[a].next)
    {
        int t=e[a].to;
        f+=dfs(t);
        for(int j=f+1; j>=cost; j--)
            for(int k=1; k<=j-cost; k++)
                dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[t][k]);
    }
    return f+cost; //¸ùÒ²ÏûºÄ1
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&w[i]);
        addedge(x,i);
    }
    dfs(0);
    printf("%d\n",dp[0][m+1]);
}

Accepted, time = 22 ms, mem = 924 KiB, score = 100

时间: 2024-10-27 02:07:34

Vijos 1180 (树形DP+背包)的相关文章

HDU 1011 Starship Troopers(树形dp+背包)

Starship Troopers Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13109    Accepted Submission(s): 3562 Problem Description You, the leader of Starship Troopers, are sent to destroy a base of

hdu1011 树形dp背包

http://acm.hdu.edu.cn/showproblem.php?pid=1011 Problem Description You, the leader of Starship Troopers, are sent to destroy a base of the bugs. The base is built underground. It is actually a huge cavern, which consists of many rooms connected with

Poj 1112 Rebuilding Roads(树形DP+背包)

题意:给你由N个点构成一颗树,问要孤立出一个有P个节点的子树最少需要删除多少条边.N的范围最大为150 N的范围不大,很容易想到在树上面做背包.把每个节点都看成一个背包,然后把每个儿子节点都看成是一组物品.为什么是一组呢,那是因为假设以儿子为根的节点的子树有S个节点,那么就有S+1种情况,要么将这整棵子树舍弃,要么从这个子树中取1-S个节点. 设f[i][j]为以i为根节点的子树,孤立出以i为根节点,一共含有j个节点的子树最少需要删除的边数(不包括删除i和他父亲的连接的那条边(假设i不是根节点)

HDU 1561 The more, The Better(树形dp+背包)

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6000    Accepted Submission(s): 3548 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物.但由于地理位置原因,有些城堡不能直接攻

POJ3345---Bribing FIPA(树形dp+背包)

Description There is going to be a voting at FIPA (Fédération Internationale de Programmation Association) to determine the host of the next IPWC (International Programming World Cup). Benjamin Bennett, the delegation of Diamondland to FIPA, is tryin

URAL_1018 Binary Apple Tree 树形DP+背包

这个题目给定一棵树,以及树的每个树枝的苹果数量,要求在保留K个树枝的情况下最多能保留多少个苹果 一看就觉得是个树形DP,然后想出 dp[i][j]来表示第i个节点保留j个树枝的最大苹果数,但是在树形过程中,有点难表示转移 后来看了下大神的做法才知道其实可以用背包来模拟 树枝的去留,其实真的是个背包诶,每个子树枝就相当于物品,他占用了多少树枝量,带来多少的收益,就是用背包嘛,于是用树形DP+背包就可以做了 #include <iostream> #include <cstdio> #

hdu1561 树形dp+背包

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; #define ll long

Ural 1018 (树形DP+背包+优化)

题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17662 题目大意:树枝上间连接着一坨坨苹果(不要在意'坨'),给定留下m根树枝,问最后剩下的最多苹果是多少. 解题思路: 其实意思和Vijos 1180(选课)的意思差不多.只不过权在边而已. 首先建无向图dfs. for(f+1...j....cost) for(1....k...j-cost) 其中f为当前已经dfs子结点个数.之所以+1,是因为当前点也需要

P2015 二叉苹果树[树形dp+背包]

题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来描述一根树枝的位置.下面是一颗有4个树枝的树 2 5 \ / 3 4 \ / 1 现在这颗树枝条太多了,需要剪枝.但是一些树枝上长有苹果. 给定需要保留的树枝数量,求出最多能留住多少苹果. 解析 一道很简单的树形dp,然而我调了半天都没调出来,就是菜. 容易看出状态\(dp[x][i]\)表示以\(