zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",dp[1][m]);
        }
        return 0;
    }
  • 相关阅读:
    软件测试原则
    java知识点
    jquery取值
    Javaweb命名规则
    @ResponseBody
    jquery ajax 方法及各参数详解
    @RequestMapping用法详解
    eclipse+android+opencv环境搭建的步骤
    Java中的内部类(回调)
    OpenCV直方图(直方图、直方图均衡,直方图匹配,原理、实现)
  • 原文地址:https://www.cnblogs.com/d-e-v-i-l/p/5333628.html
Copyright © 2011-2022 走看看