zoukankan      html  css  js  c++  java
  • 洛谷P2515 [HAOI2010]软件安装 (树形背包+tarjan缩点)

    [HAOI2010]软件安装

    分析:

    每个点最多依赖一个点,最后建出来的图可能成环,也可能是一棵树。

    先用tarjan缩点,对缩点后的图建边,会建成一颗森林(有成环点缩点后孤立)

    用一个超级源点向入度为0的点连边,跑一遍树形dp

    注意:
    1. 弄清楚依赖关系

    2. 树形dp中要固定选父节点

    #include<bits/stdc++.h>
    using namespace std;
    #define N 105
    #define ri register int
    int to[N],nex[N],head[N],tot=0,dp[N][N*5],flag[N],n,m,ru[N];
    int dfn[N],low[N],stk[N],Ti=0,cnt=0,bel[N],w1[N],v1[N],w2[N],v2[N],top=0;
    vector<int> e[N];
    vector<int> scc[N];
    void add(int a,int b) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++Ti;
        stk[++top]=x; flag[x]=true;
        for(ri i=head[x];i;i=nex[i]){
            int v=to[i];
            if(!dfn[v]){
                tarjan(v);
                low[x]=min(low[x],low[v]);
            }
            else if(flag[v]) low[x]=min(low[x],dfn[v]);
        }
        if(low[x]==dfn[x]){
            cnt++;
            do{
                int tmp=stk[top];
                scc[cnt].push_back(tmp); flag[tmp]=0;
                bel[tmp]=cnt;
            }while(stk[top--]!=x);
        }
    }
    void dfs(int u)
    {
        for(ri i=v2[u];i<=m;++i) dp[u][i]=w2[u];
        for(ri i=0;i<e[u].size();++i){
            int v=e[u][i];
            dfs(v);
            for(ri j=m;j>=v2[u];--j)
             for(ri k=0;k<=j-v2[u];++k)//j-v2[u]固定了一定会选到父节点!! 
              dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
        }
    }
    int main()
    {
        int d;
        scanf("%d%d",&n,&m);
        for(ri i=1;i<=n;++i) scanf("%d",&v1[i]);
        for(ri i=1;i<=n;++i) scanf("%d",&w1[i]);
        for(ri i=1;i<=n;++i) { scanf("%d",&d); if(d) add(d,i); }
        for(ri i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
        for(ri i=1;i<=n;++i){
            w2[bel[i]]+=w1[i]; v2[bel[i]]+=v1[i];
            for(ri j=head[i];j;j=nex[j]){
                int v=to[j];
                if(bel[i]!=bel[v])
                 e[bel[i]].push_back(bel[v]),ru[bel[v]]++;
            }
        }
        for(ri i=1;i<=cnt;++i) if(!ru[i]) e[cnt+1].push_back(i);
        dfs(cnt+1);
        printf("%d",dp[cnt+1][m]);/**/
    }
    /*
    3 10
    5 5 6
    2 3 4
    0 1 1
    */
    View Code
  • 相关阅读:
    编码
    浏览器翻页
    验证码识别
    时间
    phantomjs配置
    产品
    java范型的理解
    使用JDBC连接数据库
    垃圾回收机制
    java的内存区域 && java内存模型
  • 原文地址:https://www.cnblogs.com/mowanying/p/11656382.html
Copyright © 2011-2022 走看看