1. 程式人生 > >【hdu】1011 Starship Troopers【樹形揹包】

【hdu】1011 Starship Troopers【樹形揹包】

【題意】:有一顆樹,樹的節點編號為1-n,1為根節點,每個節點上會有x個敵人,y個寶藏,現在你從1號節點出發,率領m個友方單位,只有攻佔了父節點才能繼續攻佔子節點,如果你在一個節點的兵力*20>=敵人數,你就可以得到這個節點中的寶藏,並且這些士兵就永久駐紮在這個節點了,並且所有士兵不能走回頭路(注意這個條件非常重要,我在這裡WA了2次,這個條件就意味著,就算每個節點的敵人數量都是0,也至少需要一個士兵才能獲得寶藏,並且這個士兵只能選擇樹上的一條鏈走到底)

【題解】:主要是題目條件比較坑,其他的就是裸的樹形揹包,在樹上進行揹包,思想很簡單dp[i][j]代表以i節點為根的子樹派出兵力j所能得到最多的寶藏數  

遞推式dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k])

其中u為父節點 j為給以u為根的子樹分配的兵力數 v為子節點 k為分配給以v為根節點的子樹的兵力  

其中只有攻佔了父節點才能繼續攻佔子節點這個條件,只要在對每個點進行揹包的時候強制留下w[u]個士兵即可(w[u]為攻佔u節點所需要的士兵數)

其他細節看程式碼

#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define PB push_back
#define MP make_pair
#define ll __int64
#define MS(a,b) memset(a,b,sizeof(a))
#define LL (rt<<1)
#define RR (rt<<1|1)
#define lson l,mid,LL
#define rson mid+1,r,RR
#define pii pair<int,int>
using namespace std;
const int MAXN=1e2+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int dp[MAXN][MAXN];
int w[MAXN],val[MAXN];
int m;
vector<int>G[MAXN];
void dfs(int u,int fa)
{
    for(int j=w[u];j<=m;j++)dp[u][j]=val[u];//初始化 因為必須要先攻下父節點才能往子節點走 所有父節點是必須要取得
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==fa)continue;
        dfs(v,u);
        for(int j=m;j>=w[u];j--)//列舉在u及其子樹的派兵量 倒著列舉是和揹包一樣 防止重複使用
            for(int k=1;k<=j-w[u];k++)//列舉分配給v及其子樹的士兵量 因為至少有一個士兵才能有得到大腦 不管敵人數量是不是0 
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);//上限是j-w[u]是因為u節點必須要攻佔 
    }
}
int main()
{//freopen("C:\\Users\\Administrator\\Desktop\\input.txt","r",stdin);
    int n;
    while(scanf("%d%d",&n,&m),n!=-1||m!=-1){
        MS(dp,0);
        for(int i=1;i<=n;i++){
            int tmp;
            scanf("%d%d",&tmp,&val[i]);
            w[i]=(tmp+19)/20;//算攻佔一個洞穴需要幾個士兵
            G[i].clear();
        }
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].PB(v);G[v].PB(u);
        }
        if(m==0){printf("0\n");continue;}//至少要有人才能拿到大腦
        dfs(1,-1);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}