首页 > 其他 > 详细

【HAOI2010】软件安装

时间:2019-10-04 22:10:20      阅读:71      评论:0      收藏:0      [点我收藏+]
需要安装n个软件,每个软件会占用wi的空间,价值为vi
计算机总容量为M,要使这些软件的价值尽可能大
但软件之间存在依赖关系,即只有安装了前提软件,这个软件才有价值
求出结果

如果只是普通的依赖关系,那么这些关系构成了一棵树
显然使用树形dp,\(dp[i][j]\)表示以 \(i\) 为根的子树中使用不超过 \(j\) 的空间的最大价值

然而,由于原题面中说得很清楚(当然我这里简化版的题面看不出来……)
依赖关系可能会成一个环
比如,玩东方project的时候需要使用符卡练习器,否则连Easy难度都过不去, 这游戏就没有意义
然而如果只下载符卡练习器,而不安装东方project,这个练习器毫无意义,价值也为0
在上面这个例子里,东方project和符卡练习器互相依赖,成一个环
我们要做的就是,把这些成环的依赖关系看待成一个点,使其等价于原来的多个程序

缩点?
tarjan准备上啊

缩完以后就是一个简单地树形dp了,思路如上

代码:

#include<bits/stdc++.h>
#define N 2005
using namespace std;

int n,m;
int w[N],v[N],x[N],y[N];

struct Edge
{
    int next,to;
}edge[N<<2];
int cnt=0,head[N];

inline void add_edge(int from,int to)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    head[from]=cnt;
}

template<class T>inline void read(T &res)
{
    char c;T flag=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

int tms=0,low[N],dfn[N],color[N];
int sta[N],top=0;
bool vis[N];
int colorcnt=0;
void tarjan(int u)
{
    low[u]=dfn[u]=++tms;
    sta[++top]=u;
    vis[u]=1;
    for(register int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        ++colorcnt;
        vis[u]=0;
        while(sta[top+1]!=u)
        {
            color[sta[top]]=colorcnt;
            vis[sta[top--]]=0;
        }
    }
}

int ww[N],vv[N],idx[N];
int dp[N][N];
void dfs(int u)
{
    for(register int i=ww[u];i<=m;++i) dp[u][i]=vv[u];
    for(register int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        dfs(v);
        for(register int j=m-ww[u];j>=0;--j)
        {
            for(register int k=0;k<=j;++k)
                dp[u][j+ww[u]]=max(dp[u][j+ww[u]],dp[u][j+ww[u]-k]+dp[v][k]);

        }
    }
}

int main()
{
    read(n);read(m);
    for(register int i=1;i<=n;++i) read(w[i]);
    for(register int i=1;i<=n;++i) read(v[i]);
    for(register int i=1;i<=n;++i)
    {
        read(y[i]);
        if(!y[i]) continue;
        add_edge(y[i],i);
    }
    for(register int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    memset(edge,0,sizeof(edge));
    memset(head,0,sizeof(head));
    for(register int i=1;i<=n;++i)
    {
        vv[color[i]]+=v[i];
        ww[color[i]]+=w[i];
        if(color[i]!=color[y[i]]&&y[i])
        {   
            add_edge(color[y[i]],color[i]);
            idx[color[i]]++;
        }
    }
    for(register int i=1;i<=colorcnt;++i)
        if(!idx[i]) add_edge(colorcnt+1,i);
    dfs(colorcnt+1);
    printf("%d\n",dp[colorcnt+1][m]);
    return 0;
}

【HAOI2010】软件安装

原文:https://www.cnblogs.com/tqr06/p/11623432.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!