• bzoj 2427 [HAOI2010]软件安装


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

    今天的考试题……没有想到环的情况。

    希望自己能打出正确的tarjan缩点板子……

    main函数里还有各种需要注意的地方。比如tarjan要从rd为0的点或者环上的任意一点进入。不过bzoj好像不判rd为0,只看dfn也行。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=105,M=505;
    int n,m,tv[N],tw[N],v[N],w[N],head[N],txnt,xnt,dp[N][M];
    int cnt,col[N],stack[N],top,siz[N],ans,dfn[N],low[N],tim;
    bool ins[N],rd[N];
    struct Ed{
        int next,fr,to;Ed(int n=0,int f=0,int t=0):next(n),fr(f),to(t) {}
    }ed[M<<1];
    void tarjan(int cr)
    {
        stack[++top]=cr;ins[cr]=1;
        dfn[cr]=low[cr]=++tim;
        for(int i=head[cr],to;i;i=ed[i].next)
            if(ins[to=ed[i].to])low[cr]=min(low[cr],dfn[to]);
            else if(!dfn[to])tarjan(to),low[cr]=min(low[cr],low[to]);//!dfn[to]才进入!!!
        if(low[cr]==dfn[cr])    //这样才... 
        {
            cnt++;
            while(stack[top]!=cr)
            {
                int k=stack[top--];
                tv[cnt]+=v[k];tw[cnt]+=w[k];col[k]=cnt;ins[k]=0;
            }
            col[cr]=cnt;ins[cr]=0;top--;
            tv[cnt]+=v[cr];tw[cnt]+=w[cr];//别忘了 
        } 
    }
    void dfs(int cr)
    {
        siz[cr]=tv[cr];dp[cr][tv[cr]]=tw[cr];
        for(int i=head[cr],to;i;i=ed[i].next)
        {
            dfs(to=ed[i].to);
            for(int j=min(m,siz[cr]+siz[to]);j>tv[cr];j--)
                for(int k=max(0,j-siz[cr]);k<=siz[to]&&k<=(j-tv[cr]);k++)
                    dp[cr][j]=max(dp[cr][j],dp[to][k]+dp[cr][j-k]);
            siz[cr]+=siz[to];
        }
    }
    int main()
    {
    //    freopen("software.in","r",stdin);
    //    freopen("software.out","w",stdout);
        scanf("%d%d",&n,&m);int x;
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);if(!x)continue;
            ed[++xnt]=Ed(head[x],x,i);head[x]=xnt;rd[i]++;
        }
        for(int i=1;i<=n;i++)if(!rd[i])tarjan(i);
        for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);//
        memset(head,0,sizeof head);memset(rd,0,sizeof rd);
        for(int i=1,u,v;i<=xnt;i++) if((u=col[ed[i].fr])!=(v=col[ed[i].to]))
            ed[++txnt]=Ed(head[u],u,v),head[u]=txnt,rd[v]=1;
        for(int i=1;i<=cnt;i++)if(!rd[i])ed[++txnt]=Ed(head[0],0,i),head[0]=txnt;
        dfs(0);
        for(int i=0;i<=m;i++)ans=max(ans,dp[0][i]);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    如何删除一个CSDN上自己上传的资源
    ubuntu 安装 boost
    C#-提取网页中的超链接
    数组地址详解
    约瑟夫环-源码
    树的基础概念(二)
    二叉树的主要操作
    二叉树的简介及链式结构实现
    树的基础概念
    栈实现数的进制转换
  • 原文地址:https://www.cnblogs.com/Narh/p/9259302.html
Copyright © 2020-2023  润新知