• bzoj1017(JSOI2008)魔兽地图


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

    钱数很少,所以它也能压进状态里。

    还有向上贡献几个物品。所以状态就是第 i 号物品,向上贡献 j 个,总共花 k 元的当前就能得到的力量。

    然后可以树形dp。

    不同的是平常的树形dp,该点的值就顺便充当前 r 个子树的值;遍历完子树就完成自己的值。

      但这里的状态里有一个“向上贡献 j 个”,不太好弄。所以另开一个 g ,只关注花了多少钱和带来多少力量。

      为了能用这个g转移到dp,不出现花了某些钱其实买不够向上贡献的 j 个当前物品的情况,应该把“总共买 l 个当前物品”放在最外面枚举。

        并且是倒序,为了沿用上一轮的g值。

    **不知为何,自己的代码比别人慢了好多!!我觉得没什么不同呀……以后再来看看吧。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int N=55,M=2005;const ll INF=0x7fffffff;
    int n,m,head[N],xnt,du[N];
    ll a[N],L[N],c[N],dp[N][N<<1][M],g[N][M],h[N][M],ans;//dp[][N<<1][]不能dp[][N][] 
    struct Edge{
        int next,to;ll w;
        Edge(int n=0,int t=0,ll w=0):next(n),to(t),w(w) {}
    }edge[N];
    void dfs(int cr)
    {
        if(!head[cr])
        {
            L[cr]=min(L[cr],m/c[cr]);
            for(int i=0;i<=L[cr];i++)
                for(int j=0;j<=i;j++)
                    dp[cr][j][i*c[cr]]=(i-j)*a[cr];
            return;
        }
        L[cr]=INF;
        for(int i=head[cr],v;i;i=edge[i].next)
        {
            dfs(v=edge[i].to);L[cr]=min(L[cr],L[v]/edge[i].w);
            c[cr]+=c[v]*edge[i].w;        //只是用来限制L[cr] 
        }
        L[cr]=min(L[cr],m/c[cr]);
        memset(g,-2,sizeof g);//g只和子树阶段、钱有关,因为dp涉及"向上贡献几个",所以不方便同时表示前几个子树的力量值 
        g[0][0]=0;
        for(int l=L[cr];l>=0;l--)//g不重赋值,所代表的状态应该足以合成当前的l个当前装备;所以需倒序 
        {
            int tot=0;
            for(int i=head[cr];i;i=edge[i].next)
            {
                tot++;
                for(int k=0;k<=m;k++)//用了k钱
                    for(int j=0;j<=k;j++)//j钱给v
                        g[tot][k]=max(g[tot][k],g[tot-1][k-j]+dp[edge[i].to][l*edge[i].w][j]);//k-j钱给之前的子树 
            }
            for(int j=0;j<=l;j++)
                for(int k=0;k<=m;k++)
                    dp[cr][j][k]=max(dp[cr][j][k],g[tot][k]+a[cr]*(l-j));//子树们的节余+自己的节余 
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);char ch;int u,x;ll z;
        memset(L,1,sizeof L);
        memset(dp,-2,sizeof dp);//////
        for(int i=1;i<=n;i++)
        {
            scanf("%lld %c",&a[i],&ch);
            if(ch=='B')
            {
                scanf("%lld%lld",&c[i],&L[i]);
            }
            else
            {
                scanf("%d",&u);
                for(int j=1;j<=u;j++)
                {
                    scanf("%d%lld",&x,&z);
                    edge[++xnt]=Edge(head[i],x,z);head[i]=xnt;du[x]++;
                }
            }
        }
        int tot=0;
        for(int i=1;i<=n;i++)
            if(!du[i])
            {
                dfs(i);tot++;
                for(int k=0;k<=m;k++)//总共 
                    for(int j=0;j<=m;j++)//给之前的树
                        h[tot][k]=max(h[tot][k],h[tot-1][j]+dp[i][0][k-j]);
            }
        for(int i=0;i<=m;i++)ans=max(ans,h[tot][i]);
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    js开发笔记
    安全相关开发笔记
    常用.NET库使用总结
    Windows使用总结
    .NET Web开发笔记
    Unity插件使用总结
    WinForm开发笔记
    C#开发笔记
    iTunes使用总结
    Mac使用总结
  • 原文地址:https://www.cnblogs.com/Narh/p/9141805.html
Copyright © 2020-2023  润新知