• bzoj1017 [JSOI2008]魔兽地图DotR——DP


     题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1017

    好难想的状态啊!f[i][j][k]表示i号物品有j个向上贡献,一共花了k钱的最大力量;

    g[i][j]用在子树中,表示前i个子树花j钱的最大值;

    调了半上午,终于发现原来是少看了一个范围,f的第二维的范围不是51而是100啊啊啊啊啊啊!

    除此之外此题也有很多要注意的地方,写在注释里了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int const maxn=55,maxm=2005,inf=1000000000;
    int n,m,L[maxn],M[maxn],P[maxn],head[maxn],ct;
    int f[maxn][maxn<<1][maxm],g[maxn][maxm],rd[maxn],h[maxn][maxm];
    struct N{
        int to,next,w;
        N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
    }edge[20005];
    void dp(int x)
    {
        if(!head[x])//叶子 
        {
            L[x]=min(L[x],m/M[x]);//!
            for(int i=0;i<=L[x];i++)//有i个 
                for(int j=0;j<=i;j++)//贡献j个 
                    f[x][j][M[x]*i]=P[x]*(i-j);
            return;//!!!!!!!!!!
        }
        L[x]=inf;//!高级装备原本没有限制 
        for(int i=head[x],u;i;i=edge[i].next)
        {
            u=edge[i].to;
            dp(u);
            L[x]=min(L[x],L[u]/edge[i].w);
            M[x]+=M[u]*edge[i].w;//
        }
        L[x]=min(L[x],m/M[x]);
        memset(g,-0x3f,sizeof g);//!!
        g[0][0]=0;//!!
        for(int l=L[x];l>=0;l--)//x物品有l个  //倒序!  //l可以有0个!!!!!!!!!!! 
        {
            int tot=0;
    //        memset(g,0,sizeof g);//放在外面! 
            for(int i=head[x],v;i;i=edge[i].next)
            {
                v=edge[i].to;
                tot++;
                for(int j=0;j<=m;j++)//一共有j钱 
                    for(int k=0;k<=j;k++)//给v k钱 
                        g[tot][j]=max(g[tot][j],g[tot-1][j-k]+f[v][l*edge[i].w][k]);
                        //g每次不会重新赋初值,所以需要l倒序来保证本次一定可以合成l个x物品 
            }
            for(int j=0;j<=l;j++)
                for(int k=0;k<=m;k++)
                    f[x][j][k]=max(f[x][j][k],g[tot][k]+P[x]*(l-j));
        } 
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        char dc;
    //    memset(L,0x3f,sizeof L);
        memset(f,-0x3f3f3f3f,sizeof f);
        for(int i=1,x,a,b;i<=n;i++)
        {
            scanf("%d",&P[i]);
            cin>>dc;
            if(dc=='A')
            {
                scanf("%d",&x);
                while(x--)
                {
                    scanf("%d%d",&a,&b);
                    edge[++ct]=N(a,head[i],b);head[i]=ct;
                    rd[a]++;
                }
            }
            else scanf("%d%d",&M[i],&L[i]);
        }
        int tot=0;
        for(int i=1;i<=n;i++)
            if(!rd[i])
            {
                tot++;
                dp(i);
                for(int j=0;j<=m;j++)
                    for(int k=0;k<=j;k++)
                        for(int l=0;l<=L[i];l++)
                            h[tot][j]=max(h[tot][j],h[tot-1][k]+f[i][l][j-k]);
            }
        int ans=0;
        for(int j=0;j<=m;j++)ans=max(ans,h[tot][j]);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    关于一道PHP面试题的解法
    ThinkPHP学习(二)
    ThinkPHP学习(一)
    Apache 创建虚拟主机目录和设置默认访问页面
    awk全集
    初识云计算&openstack
    Python collections
    Python 函数/高阶函数
    Python dic/set/迭代
    python matplotlib 图标绘制
  • 原文地址:https://www.cnblogs.com/Zinn/p/9139072.html
Copyright © 2020-2023  润新知