【HDU1561】The more, The Better | 树形依赖背包、树形dp

题目大意:

ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?

题目思路:

这种类型的树形dp就比较明显了

考虑dp[u][k]代表从u节点出发选了k个物品的最大值,因为存在依赖关系;

所以注意状态转移时,特别注意dp[u][0]这个不合法状态不要计入到转移内

由于全图是一个森林,那么就对每个树全部跑一遍依赖背包

对于全图这个森林跑一遍分组背包即可

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 2e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
vector<int>v[maxn];
ll dp[2005][2005];
int num[maxn],in[maxn];
ll dpc[2005];
void dfs(int u){
    dp[u][1] = num[u];
    for(int e:v[u]){
        dfs(e);
        for(int k=m;k>=1;k--)
            for(int j=1;j<=k-1;j++)
                dp[u][k] = max(dp[u][k],dp[u][k-j]+dp[e][j]);
    }
}
int main(){
    while(~scanf("%lld%lld",&n,&m)&&n&&m){
        for(int i=1;i<=n;i++) in[i] = 0,v[i].clear();
        for(int i=1;i<=n;i++){
            int x;read(x);read(num[i]);
            if(x) v[x].push_back(i),in[i]++;
        }
        for(int i=1;i<=n;i++)
            for(int k=0;k<=m;k++)
                dp[i][k] = 0;
        for(int i=1;i<=n;i++)
            if(!in[i])
                dfs(i);
        for(int i=0;i<=m;i++) dpc[i] = 0;
        for(int i=1;i<=n;i++){
            if(!in[i]){
                for(int k=m;k>=0;k--){
                    for(int j=0;j<=k;j++){
                        dpc[k] = max(dpc[k],dpc[k-j] + dp[i][j]);
                    }
                }
            }
        }
        ll ans = 0;
        for(int i=0;i<=m;i++) ans = max(ans,dpc[i]);
        printf("%lld\n",ans);
    }
    return 0;
}

/***
4 3
0 0
1 0
2 0
3 1
****/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/111314289
今日推荐