HDU4044 GeoDefense(树形dp+分组背包)

题意:

给定n个节点组成的树,1为敌方基地,叶子结点为我方结点。我们可以在每个结点安放炮台,至多一炮,然后就可以打炮,每个结点有ki种炮,每种炮有一个花费 和一个能量(能量对应着打掉敌人多少hp)。敌人可能往一个结点的每条分支跑,所以要想保证守住阵地,就要保证每个分支都要安放炮台。最后问怎么打炮,才 能使打掉的敌人hp最多。

思路:

树形dp,dp[i][j]表示以i为根节点消耗j能量所打掉的最大hp

这道题有个坑,就是建炮的花费有可能是0,这样需要处理一下,避免建多个炮。

先附上自己的代码(889ms):

 

/* ***********************************************
Author        :devil
Created Time  :2016/3/29 16:54:34
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
#define inf 0x7f7f7f7f
#define N 1010
#define M 210
int n,m,dp[N][M];
vector<int>eg[N];
vector<int>price[N],power[N];
void init()
{
    for(int i=0;i<N;i++)
    {
        eg[i].clear();
        price[i].clear();
        power[i].clear();
    }
}
void dfs(int u,int fa)
{
    if(eg[u].size()==1&&u!=1)
    {
        for(int i=0;i<=m;i++)
            dp[u][i]=0;
        for(int i=0;i<=m;i++)
        {
            for(int j=0;j<price[u].size();j++)
            {
                if(price[u][j]<=i)
                    dp[u][i]=max(dp[u][i],power[u][j]);
            }
        }
        return ;
    }
    for(int i=0;i<=m;i++)
        dp[u][i]=inf;
    for(int i=0;i<eg[u].size();i++)
    {
        int to=eg[u][i];
        if(to==fa) continue;
        dfs(to,u);
        for(int j=m;j>=0;j--)
        {
            int tmp=0;
            for(int k=0;k<=j;k++)
                tmp=max(tmp,min(dp[u][j-k],dp[to][k]));
            dp[u][j]=tmp;
        }
    }
    for(int i=m;i>=0;i--)
    {
        int tmp=dp[u][i];
        for(int j=0;j<price[u].size();j++)
            if(price[u][j]<=i)
            {
                if(price[u][j])
                    dp[u][i]=max(dp[u][i],dp[u][i-price[u][j]]+power[u][j]);
                else dp[u][i]=max(dp[u][i],tmp+power[u][j]);
            }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int t,x,y,q;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            eg[x].push_back(y);
            eg[y].push_back(x);
        }
        scanf("%d",&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&q);
            while(q--)
            {
                scanf("%d%d",&x,&y);
                price[i].push_back(x);
                power[i].push_back(y);
            }
        }
        dfs(1,0);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}

 

然后又参考了网上的另一种做法,把每个节点每种花费的最大hp消耗存在数组里,写起来方便些,遍历的要多,时间复杂度要高一些,附上代码(998ms):

/* ***********************************************
Author        :devil
Created Time  :2016/3/29 16:58:28
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
#define inf 0x7f7f7f7f
#define N 1010
#define M 210
int n,m,dp[N][M],hp[N][M];
vector<int>eg[N];
void init()
{
    for(int i=0;i<N;i++)
        eg[i].clear();
    memset(hp,0,sizeof(hp));
}
void dfs(int u,int fa)
{
    if(eg[u].size()==1&&u!=1)
    {
        for(int i=0;i<=m;i++)
            dp[u][i]=hp[u][i];
        return ;
    }
    for(int i=0;i<=m;i++)
        dp[u][i]=inf;
    for(int i=0;i<eg[u].size();i++)
    {
        int to=eg[u][i];
        if(to==fa) continue;
        dfs(to,u);
        for(int j=m;j>=0;j--)
        {
            int tmp=0;
            for(int k=0;k<=j;k++)
                tmp=max(tmp,min(dp[u][j-k],dp[to][k]));
            dp[u][j]=tmp;
        }
    }
    for(int i=m;i>=0;i--)
        for(int j=0;j<=i;j++)
            dp[u][i]=max(dp[u][i],dp[u][i-j]+hp[u][j]);
}
int main()
{
    //freopen("in.txt","r",stdin);
    int t,x,y,q;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            eg[x].push_back(y);
            eg[y].push_back(x);
        }
        scanf("%d",&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&q);
            while(q--)
            {
                scanf("%d%d",&x,&y);
                hp[i][x]=max(hp[i][x],y);
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                hp[i][j]=max(hp[i][j],hp[i][j-1]);
        dfs(1,0);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}

 

posted on 2016-03-29 17:00  恶devil魔  阅读(184)  评论(0编辑  收藏  举报

导航