加强版金明的预算方案

题面粘上:

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己与用的很宽敞的房间。
更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要丌超过
N 元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件不附件,附件是从属
于某个件的,下表就是一些主件不附件的例子:
主件 附件
电脑 打印机,扫描仪书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的件。每个主件可以有很多个附件。附件可能
有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的 N 元。于是,他把每件物品规定
了一个重要度,分为 5 等:用整数 1−5 表示,第 5 等最重要。他还从因特网上查到了每件物品的
价格(都是在 10 元以内)。他希望在丌超过 N 元(可以等于 N 元)的前提下,使每件物品的价格
不重要度的乘积的总和最大。
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j1,j2,...,jk,则
所求的总和为:
v[j1]×w[j1]+v[j2]×w[j2]+...+v[jk]×w[jk]
请你帮助金明设计一个满足要求的购物单。

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

加强之处:可以有附件的附件(结果我读错了,以为是原题)。

树形dp,很裸,但是卡常会很厉害,还有O(n^2)的dp很容易写成O(n^3)。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 8050

int n,m;
int v[N],p[N],hed[N],cnt;
struct ED
{
    int to,nxt;
}e[2*N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
int dp[N][N];
int dfs(int u)
{
    int ret = v[u];
    dp[u][ret]=v[u]*p[u];
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        int now = dfs(to);
        if(j==hed[u])
        {
            ret += now;
            for(int k = v[u];k<=ret;k++)
            {
                dp[u][k]=dp[to][k-v[u]]+v[u]*p[u];
            }
        }else
        {
            for(int a = ret;a>=v[u];a--)
            {
                for(int b = 0;b<=now;b++)
                {
                    if(a+b>n)break;
                    if(dp[u][a+b]<dp[u][a]+dp[to][b])dp[u][a+b]=dp[u][a]+dp[to][b];
                }
            }
            ret+=now;
        }
    }
    return ret;
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int q,i=1;i<=m;i++)
    {
        scanf("%d%d%d",&v[i],&p[i],&q);
        ae(q,i);
    }
    dfs(0);
    int ans = 0;
    for(int i=1;i<=n;i++)
    {
        ans = max(ans,dp[0][i]);
    }
    printf("%d\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

从dalao那里学来的O(n^2)神奇dfs。

posted @ 2018-09-03 20:41  LiGuanlin  阅读(140)  评论(0编辑  收藏  举报