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;
}

 

posted on 2018-07-03 16:33  Narh  阅读(114)  评论(0编辑  收藏  举报

导航