• [BZOJ 2427] 软件安装


    Link:

    BZOJ 2427 传送门

    Solution:

    只看样例的话会以为是裸的树形$dp$……

    但实际上题目并没有说明恰好仅有一个物品没有依赖项

    因此原图可能由是由多棵树与多个图组成的

    先跑一遍$tarjan$求出每个图中的$SCC$,缩点将原图转化为森林

    再设置一个根,将森林转换成一棵树$dp$即可:$dp[i][j]=max{ dp[i][k]+dp[son[i]][j-k]}$

    为了保证依赖条件满足,每棵子树的根都必须要选择,因此返回前还要再刷一遍:$dp[i][j]=dp[i][j-w_i]+v_i$

    Tip:$dp$时要注意$k$也要逆序枚举,因为$w_i$可能为0

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAXN=505;
    struct edge{int nxt,to;}e[MAXN<<2];
    stack<int> st;
    int f[MAXN],head[MAXN],in[MAXN],S;
    int instack[MAXN],vis[MAXN],col[MAXN],dfn[MAXN],low[MAXN];
    int n,m,x,dp[MAXN][MAXN],w[MAXN],v[MAXN],sw[MAXN],sv[MAXN],tot,cnt,idx;
    
    void add_edge(int from,int to)
    {e[++tot].nxt=head[from];e[tot].to=to;head[from]=tot;}
    
    void tarjan(int x)
    {
        dfn[x]=low[x]=++idx;
        instack[x]=vis[x]=true;st.push(x);
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(!vis[e[i].to])
                tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);
            else if(instack[e[i].to])
                low[x]=min(low[x],low[e[i].to]);
        }
        if(dfn[x]==low[x])
        {
            int t=-1;cnt++;
            while(t!=x)
            {
                t=st.top();st.pop();
                instack[t]=false;col[t]=cnt;
                sw[cnt]+=w[t];sv[cnt]+=v[t];
            }
        }
    }
    
    void dfs(int x,int anc)
    {
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(e[i].to==anc) continue;
            dfs(e[i].to,x);
            for(int j=m-sw[x];j>=0;j--)
                for(int k=j;k>=0;k--)//k也要保持逆序 
                    dp[x][j]=max(dp[x][j],dp[x][k]+dp[e[i].to][j-k]);
        }
        for(int j=m;j>=0;j--)
            if(j>=sw[x]) dp[x][j]=dp[x][j-sw[x]]+sv[x];
            else dp[x][j]=0;
    }
    
    int main()
    {
        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;i<=n;i++)
        {
            scanf("%d",&f[i]);
            if(f[i]) add_edge(f[i],i);
        }
        
        for(int i=1;i<=n;i++)//原图不一定连通 
            if(!vis[i]) tarjan(i);
        
        tot=0;S=cnt+1;
        memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++)
            if(f[i]&&col[i]!=col[f[i]])
                add_edge(col[f[i]],col[i]),in[col[i]]++;
        for(int i=1;i<=cnt;i++)//建立根 
            if(!in[i]) add_edge(S,i);
        
        dfs(S,0);
        printf("%d",dp[S][m]);
        
        return 0;
    }
  • 相关阅读:
    B. Pasha and Phone
    GCD(关于容斥原理)
    二分乘法
    Lucky7(容斥原理)
    E. Devu and Flowers
    最大公约数最小公倍数
    leetcode每日刷题计划--day55
    Titanic--kaggle竞赛入门-生存预测
    做题记录--day54
    机器学习上机作业1记录 && 相关知识点复习
  • 原文地址:https://www.cnblogs.com/newera/p/9311911.html
Copyright © 2020-2023  润新知