HDU 4003 Find Metal Minaral 树上瞎搞分组背包

对于分组背包,每组选且只选一件商品的写法只想出了二维数组的写法。

dp[s][k] 表示 在前s类中选取价格为 k 的商品的最优解。

dp[s][k] = max( dp[s-1][k-product[s][j].c] + product[s][j].w)。dp[s][k]每次只会有dp[s-1]更新得到,保证了前s-1类商品的选取。


对于此题,可以把每棵子树的情况看成一类商品,递归求解。

dp[s][k]表示在s子树上投入k个机器人时的最优解。

当k == 0时,表示在s点投入1个机器人,且此机器人又返回s点,当k >= 1时,表示在s点投入k个机器人且都不返回的s结点时的最优解。

更新时显而易见的有,每棵子树选取一种情况下最优解来更新根节点的最优解。写法即为上面的二位分组背包,但是此题貌似范围较大建议滚动数组。


#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>
#include <map>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long LL
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 1000000007
#define LM(a,b) (((ULL)(a))<<(b))
#define RM(a,b) (((ULL)(a))>>(b))

using namespace std;

const LL MAXN = 10010;

struct N
{
    int u,v,w,next;
} edge[MAXN*2];

int head[MAXN];

int Top;

void Link(int u,int v,int w = -1)
{
    edge[Top].u = u;
    edge[Top].v = v;
    edge[Top].w = w;
    edge[Top].next = head[u];
    head[u] = Top++;
}

void Init_head_Top(int n)
{
    memset(head,-1,sizeof(int)*(n+2));
    Top = 0;
}

int dp[12][MAXN];

int dfs(int s,int pre,int k)
{
    if(dp[k][s] != -1)
        return dp[k][s];

    int val[2][14];

    memset(val,-1,sizeof(val));

    int site = 1;

    bool mark = false;

    for(int p = head[s]; p != -1; p = edge[p].next)
    {
        if(edge[p].v != pre)
        {
            if(mark == false)
            {
                mark = true;

                memset(val[site&1],-1,sizeof(val[site&1]));

                for(int j = 0; j <= k; ++j)
                {
                    int t = dp[j][edge[p].v] == -1 ? dfs(edge[p].v,s,j) : dp[j][edge[p].v];

                    if(j == 0)
                        val[site&1][j] = t + edge[p].w*2;
                    else
                        val[site&1][j] = t + edge[p].w*j;
                }
            }
            else
            {
                memset(val[site&1],-1,sizeof(val[site&1]));

                for(int i = 0; i <= k; ++i)
                {
                    if(val[(site-1)&1][i] != -1)
                    {
                        for(int j = k; j >= 0; --j)
                        {
                            if(i+j <= k)
                            {
                                int temp;

                                int t = dp[j][edge[p].v] == -1 ? dfs(edge[p].v,s,j) : dp[j][edge[p].v];

                                if(j == 0)
                                    temp = t + edge[p].w*2 + val[(site-1)&1][i];
                                else
                                    temp = t + edge[p].w*j + val[(site-1)&1][i];
                                if(val[site&1][i+j] == -1 || val[site&1][i+j] > temp)
                                    val[site&1][i+j] = temp;
                            }

                        }
                    }
                }
            }
            site++;
        }
    }

    for(int i = 0;i <= k; ++i)
    {
        if(val[(site-1)&1][i] != -1)
            dp[i][s] = val[(site-1)&1][i];
       else dp[i][s] = 0;
    }

  //  cout<<"k = "<<k<<" s = "<<s<<" dp = "<<dp[k][s]<<endl;

    return dp[k][s];
}

int main()
{
    int n,s,k;

    int u,v,w;

    while(scanf("%d %d %d",&n,&s,&k) != EOF)
    {
        Init_head_Top(n);

        for(int i = 0; i <= k; ++i)
        {
            memset(dp[i],-1,sizeof(int)*(n+2));
        }

        for(int i = 1; i < n; ++i)
        {
            scanf("%d %d %d",&u,&v,&w);
            Link(u,v,w);
            Link(v,u,w);
        }

        dfs(s,-1,k);

        int Min = dp[1][s];

        for(int i = 1; i <= k; ++i)
        {
            Min = min(Min,dp[i][s]);
           // cout<<"dp = "<<dp[i][s]<<endl;;
        }

        printf("%d\n",Min);
    }

    return 0;
}











你可能感兴趣的:(HDU 4003 Find Metal Minaral 树上瞎搞分组背包)