zoukankan      html  css  js  c++  java
  • HDOJ-1011 Starship Troopers

    Description:

    你作为星际舰队舰长被派去摧毁虫族基地。基地实际上是一个巨大的洞穴,由许多空间与隧道相连。每个空间都有一些虫子,虫群之心藏在一些空间里。你的任务是摧毁整个基地,并捕获尽可能多的虫群之心。你获得一张地图,所有的空间都标有里面虫子的数量,还有可能有一个虫群之心。洞穴结构是一棵树,从入口到每个空间都有一条小路。为了尽快完成战斗,你必须在经过的每个空间留下一些舰船来对付里面的所有虫子。舰队再也不会进入以前去过的空间。

    一艘舰船可以对付20只虫子。舰船不够,只能占领一些空间,剩下的交给神经毒气(这个空间的虫群之心也会死去),同时最大化捕捉虫群之心的可能性。即只要最大限度地将占用空间的虫群之心的所有可能性加起来。

    Sample Input
    
    5 10
    50 10
    40 10
    40 20
    65 30
    70 30
    1 2
    1 3
    2 4
    2 5
    1 1
    20 7
    -1 -1
    
     
    
    Sample Output
    
    50
    7

    我们用dp[i][j]来表示当前第i个空间中派了j个舰船去获得虫群之心的概率,dp[v][k]表示当前第v个空间中派了k个舰船去获得虫群之心的概率,,v为u的一个子空间从而可以得到状态转移方程:

    dp[i][j] = max(dp[i][j],  dp[i][j-k] + dp[v][k]),总概率 f = ∑ max(dp[i][j],  dp[i][j-k] + dp[v][k]) (j<k)

    转移的过程结合了树形DP和背包DP的特点,我们枚举i的每个子节点v,并分别在i和v分派j - k和k搜舰船的概率,代码如下:

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #define MAXN 100+10
    using namespace std;
    vector<int> G[MAXN];//地图
    int dp[MAXN][MAXN];//dp[i][j]表示在空间i时 用过j个飞船 得到的抓获头目的最大概率
    int val[MAXN];//每个空间能抓获头目的概率值
    int num[MAXN];//记录每个空间 消耗的舰船数目
    int N, M;
    void DFS(int u, int fa)
    {
        for(int i = num[u]; i <= M; i++)//预处理 
            dp[u][i] = val[u];
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(v == fa) continue;
            DFS(v, u);
            //0-1 背包 求使用M个舰船 所能得到的抓获头目的最大概率
            for(int j = M; j >= num[u]; j--)
            {
                for(int k = 1; k + num[u] <= j; k++)//枚举 到v空间时 可能消耗的舰船数目
                {
                    if(dp[v][k])
                        dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k]);
                }
            }
        }
    }
    int main()
    {
        while(scanf("%d%d", &N, &M), N!=-1||M!=-1)
        {
            int a, b;
            memset(dp, 0, sizeof(dp));
            for(int i = 1; i <= N; i++)
            {
                G[i].clear();
                scanf("%d%d", &num[i], &val[i]);
                if(num[i] % 20 == 0)//求出每个洞穴需要舰船的数目
                    num[i] /= 20;
                else
                    num[i] = num[i] / 20 + 1;
            }
            for(int i = 1; i < N; i++)
            {
                scanf("%d%d", &a, &b);
                G[a].push_back(b);
                G[b].push_back(a);
            }
            if(M == 0)//单独判断
            {
                printf("0
    ");
                continue;
            }
            DFS(1, -1);
            printf("%d
    ", dp[1][M]);
        }
        return 0;
    }
    
  • 相关阅读:
    Linux- 关于windows和Linux和Mac的换行符
    HIVE- 大数据运维之hive管理
    MySQL- SQL UNION 和 UNION ALL 操作符
    【loj3044】【zjoi2019】Minimax
    【loj3043】【zjoi2019】线段树
    【uoj336】【清华集训2017】无限之环
    【cf contest 1119 F】Niyaz and Small Degrees
    【学习笔记 边分树】【uoj400】【CTSC2018】暴力写挂
    【纪中集训2019.3.25】礼物
    【纪中集训2019.3.25】芬威克树
  • 原文地址:https://www.cnblogs.com/wxx23-IOU/p/13847100.html
Copyright © 2011-2022 走看看