• bzoj2427 [HAOI2010]软件安装——缩点+树形DP


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

    今天的考试题...好不容易一次写对了树形DP,却没发现有环的情况...

    发现自己 tarjan 都不太熟了,差点没写上那个 vis 数组!

    还有点要注意的地方,如果一个环跟外部都不连边,要专门把它连到0点上去;

    然后就是普通的树形DP了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,m,w[105],v[105],head[105],ct,f[105][505],siz[105],ans,cr,col[105],hd[105],cnt;
    int dfn[105],low[105],tim,sta[105],top,vv[105],ww[105];
    bool vis[105],in[105];
    struct N{
        int to,next;
        N(int t=0,int n=0):to(t),next(n) {}
    }edge[105],ed[105];
    void dp(int x)
    {
        siz[x]=ww[x]; f[x][ww[x]]=vv[x]; f[x][0]=0;
    //    cout<<x<<endl;
    //    printf("%d head=%d
    ",x,head[x]);
        for(int j=hd[x],u;j;j=ed[j].next)
        {
            dp(u=ed[j].to);
            siz[x]+=siz[u];
            for(int i=min(m,siz[x]);i>=ww[x];i--)
                for(int k=min(i-ww[x],siz[u]);k>=0;k--)
    //            {
                    f[x][i]=max(f[x][i],f[u][k]+f[x][i-k]);
    //                if(f[x][i]>=0)printf("u=%d i=%d k=%d f[%d][%d]=%d
    ",u,i,k,x,i,f[x][i]);
    //            }    
        }
    //    printf("return:%d
    ",x);
    }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++tim;
        sta[++top]=x; vis[x]=1;//
        for(int i=head[x];i;i=edge[i].next)
        {
            int u=edge[i].to;
            if(!dfn[u])
            {
                tarjan(u);low[x]=min(low[x],low[u]);    
            }
            else if(vis[u])//
                low[x]=min(low[x],dfn[u]);
        }
        if(low[x]==dfn[x])
        {
            cr++;
            while(sta[top]!=x)
            {
                col[sta[top]]=cr;
                ww[cr]+=w[sta[top]];
                vv[cr]+=v[sta[top]];
                vis[sta[top]]=0; top--;
            }
            ww[cr]+=w[x]; vv[cr]+=v[x];
            col[x]=cr; vis[x]=0; top--;
        }
    }
    int main()
    {
    //    freopen("software.in","r",stdin);
    //    freopen("software.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        for(int i=1,x;i<=n;i++)
        {
            scanf("%d",&x);
            edge[++ct]=N(i,head[x]); head[x]=ct;
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])tarjan(i);
        for(int i=0;i<=n;i++)//
            for(int j=head[i];j;j=edge[j].next)
            {
                int u=edge[j].to;
                if(col[i]==col[u])continue;//
                ed[++cnt]=N(col[u],hd[col[i]]); hd[col[i]]=cnt;
                in[col[u]]=1;
            }
        memset(f,-3,sizeof f);
        for(int i=1;i<=cr;i++)
            if(in[i]==0){ed[++cnt]=N(i,hd[0]); hd[0]=cnt;}//注意这部分! 
        dp(0);
        for(int i=0;i<=m;i++)ans=max(ans,f[0][i]);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    LeetCode | Divide Two Integers
    LeetCode | Pow(x, n)
    LeetCode | Sqrt (x)
    LeetCode | 3 Sum
    LeetCode | Two Sum
    LeetCode | Pascal's Triangle II
    nodejs eclipse
    CentOS: Make Command not Found and linux xinetd 服务不能启动
    jquery将form表单序列化常json
    VMware Mac OS补丁安装
  • 原文地址:https://www.cnblogs.com/Zinn/p/9259052.html
Copyright © 2020-2023  润新知