• [HAOI2010]软件安装


    link

    如果没有环的话其实就是一个比较水的树形背包。但是现在有环,并且当我们选择环中任何一点时其他环上的点也都要被选择,然后就可以缩点解决环的问题。

    然后缩点后会形成一个森林,我们建虚点$0$连向各自联通块的根,然后做一个树上背包即可

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=1001;
    struct node{
        int u,v,nex;
    }x[MAXN<<1];
    struct node1{
        int u,v;
    }E[MAXN];
    int dfn[MAXN],uu[MAXN<<1],CNT,low[MAXN],cnt,n,w,num,col[MAXN],co,head[MAXN],v[MAXN],W[MAXN];
    void add(int u,int v){
        x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
    }
    int sta[MAXN],tot;
    int ww[MAXN],vv[MAXN];
    void tarjan(int f,int fath){
        dfn[f]=low[f]=++num;sta[++tot]=f;
        for(int i=head[f];i!=-1;i=x[i].nex){
            int v=x[i].v;
            if(!dfn[v]) tarjan(v,f),low[f]=min(low[f],low[v]);
            else if(!col[v]) low[f]=min(low[f],dfn[v]);
        }
        if(low[f]==dfn[f]){
            col[f]=++co;
            while(sta[tot]!=f){
                col[sta[tot]]=co;
                ww[co]+=W[sta[tot]],vv[co]+=v[sta[tot]];
                tot--;
            }
            ww[co]+=W[sta[tot]],vv[co]+=v[sta[tot]];
            tot--;
        }return;
    }
    int f[MAXN];
    bool cmp(node1 x1,node1 x2){
        if(x1.u==x2.u) return x1.v<x2.v;
        return x1.u<x2.u;
    }
    int find(int xx){
        if(f[xx]==xx) return xx;
        return f[xx]=find(f[xx]);
    }
    void merge(int x1,int x2){
        int t1=find(x1),t2=find(x2);
        f[t2]=t1;
        return;
    }
    int group[MAXN][MAXN],size[MAXN];
    void dfs(int f){
        size[f]=1;
        for(int i=head[f];i!=-1;i=x[i].nex){
            dfs(x[i].v);
            size[f]+=size[x[i].v];
        }return;
    }
    int _MAXN[MAXN],root[MAXN];
    void build(){
        for(int i=1;i<=co;i++) f[i]=i;
        for(int i=1;i<=CNT;i++)
            E[i].u=col[E[i].u],E[i].v=col[E[i].v];
        sort(E+1,E+CNT+1,cmp);
        memset(head,-1,sizeof(head)),cnt=0;
        for(int i=1;i<=CNT;i++){
            if((E[i].u!=E[i].v)&&(E[i].u!=E[i-1].u||E[i].v!=E[i-1].v)){
                merge(E[i].u,E[i].v);
                add(E[i].u,E[i].v);
            }
        }
        memset(root,-1,sizeof(root));
        for(int i=1;i<=co;i++) f[i]=find(f[i]);
        for(int i=1;i<=co;i++){
            memset(size,0,sizeof(size));
            dfs(i);
            if(size[i]>_MAXN[f[i]]){
                _MAXN[f[i]]=size[i];
                root[f[i]]=i;
            }
        }
        for(int i=1;i<=co;i++)
            if(root[i]!=-1)add(0,i);
        ww[0]=1,vv[0]=0;
        w++;
    }
    int dp[MAXN][MAXN];
    void dp_tree(int f,int fath){
        for(int k=head[f];k!=-1;k=x[k].nex){
            int v=x[k].v;
            dp_tree(v,f);
            for(int i=w;i>=0;i--){
                for(int j=i;j>=0;j--) if(i-j>=ww[v]) {
                    dp[f][i]=max(dp[f][i],dp[f][j]+dp[v][i-j]);
                }
            }
        }
        for(int i=w;i>=ww[f];i--) dp[f][i]=dp[f][i-ww[f]]+vv[f];
    }
    int main(){
        memset(head,-1,sizeof(head));
        n=read(),w=read();
        for(int i=1;i<=n;i++) W[i]=read();
        for(int i=1;i<=n;i++) v[i]=read();
        for(int i=1;i<=n;i++){
            int u=read();
            if(u) {
                E[++CNT].u=u,E[CNT].v=i;
                add(u,i); 
            }
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarjan(i,0);
        build();
        dp_tree(0,0);
        cout<<dp[0][w];
    }
    View Code
  • 相关阅读:
    Redis源码剖析之字典(dict)
    Redis源码剖析之跳表(skiplist)
    面试题精选:神奇的斐波那契数列
    awk实现类sql的join操作
    [翻译]CAP理论及其证明
    今年是冷冬?我爬了北京10年的气温,哟 还真是!
    python 等间隔抽取一定数量的数据
    操作系统-第十章-文件系统
    操作系统-第九章-虚拟内存管理
    操作系统-第八章-内存管理
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/10086524.html
Copyright © 2020-2023  润新知