• HAOI2010 软件安装


    题目链接:戳我

    如果成环的话,显然是要么里面的点一个都不选,要么全部都选qwqwq,那么我们可以将环先tarjan处理一下,将其缩成一个点。qwq(处理技巧还是比较新奇的,详情见代码)

    开始先不要和0连,处理好再连。这样之后就是一个以0为根的树形结构了qwqwq。

    (dp[i][j])表示以i为根的子树中占空间不超过j的最大收益。

    注意dp[x][0]=0一定要写在处理完当前这个点和它的子节点之后,因为存在依赖关系,要接子节点的话,这个点必须存在才可以。用-0x3f3f3f3f来表示这个点不安装。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define MAXN 510
    using namespace std;
    
    int n,m,t,top,tot,ans;
    int w[MAXN],val[MAXN],fa[MAXN],head[MAXN<<1],dp[MAXN][MAXN],sum_w[MAXN],cur[MAXN];
    int st[MAXN],dfn[MAXN],low[MAXN],in[MAXN],done[MAXN],ru[MAXN];
    bool nvis[MAXN];
    struct Edge{int nxt,to,dis;}edge[MAXN<<1];
    
    inline void add(int from,int to){edge[++t].nxt=head[from],edge[t].to=to,head[from]=t;}
    
    inline void tarjan(int x)
    {
        dfn[x]=low[x]=++tot;
        st[++top]=x;
        in[x]=1;
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]);
            else if(in[v]) low[x]=min(low[x],low[v]);
        }
        if(dfn[x]==low[x])
        {
            if(st[top]==x) --top,in[x]=0;
            else
            {
                int v,cur_w=0,cur_v=0,cur_cnt=0;
                do
                {
                    v=st[top];top--;in[v]=0;
                    cur_w+=w[v];cur_v+=val[v];
                    w[v]=val[v]=0;
                    nvis[v]=true;
                    for(int i=head[v];i;i=edge[i].nxt) add(x,edge[i].to);
                }while(v!=x);
                w[x]=cur_w,val[x]=cur_v;
                nvis[x]=false,ru[x]=0;
            }
        }
    }
    
    inline void solve(int x)
    {
        for(int i=w[x];i<=m;i++) dp[x][i]=val[x];
        sum_w[x]=w[x];
        nvis[x]=true;
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(nvis[v]==true) continue;
            solve(v);
            for(int j=0;j<=m;j++) cur[j]=-0x3f3f3f3f;
            for(int j=0;j<=sum_w[x]&&j<=m;j++)
                for(int k=0;j+k<=m&&k<=sum_w[v];k++)
                    cur[j+k]=max(cur[j+k],dp[x][j]+dp[v][k]);
            sum_w[x]+=sum_w[v];
            for(int j=0;j<=m;j++) dp[x][j]=max(dp[x][j],cur[j]);
        }
        dp[x][0]=0;
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        freopen("ce.out","w",stdout);
        #endif
        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",&val[i]);
        memset(dp,-0x3f,sizeof(dp));
        for(int i=1;i<=n;i++) 
        {
            scanf("%d",&fa[i]);
            if(fa[i]) add(fa[i],i),ru[i]++;
        }
        for(int i=0;i<=n;i++)   
            if(!dfn[i])
                tarjan(i);
        for(int i=1;i<=n;i++) 
            if(!ru[i])
                add(0,i);
        solve(0);
        for(int i=0;i<=m;i++) ans=max(ans,dp[0][i]);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    清除/var/spool/clientmqueue/目录下的文件
    欧几里德法求最大公约数
    博客园美化
    Vue.js学习笔记-script标签在head和body的区别
    C++ 继承
    Ubuntu 更换软件源/镜像源
    12306火车票余票查询&Python实现邮件发送
    饥荒联机代码
    linux内核编程入门 hello world
    windows环境下使用C++&Socket实现文件传输
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10458424.html
Copyright © 2020-2023  润新知