BZOJ 2427: [HAOI2010]软件安装

来源:互联网 发布:淘宝众筹怎么做 编辑:程序博客网 时间:2024/06/01 07:59

Description

现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

Solution
这道题蛮好==
首先构图一发。
然后发现有环。
有环的话环可以简单粗暴地看成一个物体。
所以我们先跑一边强联通,然后树形dp
最后分组背包,AC
一开始树形dp敲错了==天生对这种dp有恐惧不知为何。。
想必是儿时收到过心理阴影==

Code

/**************************************************************    Problem: 2427    User: bblss123    Language: C++    Result: Accepted    Time:120 ms    Memory:1512 kb****************************************************************/#include<iostream>#include<string.h>#include<stdio.h>#include<algorithm>#include<vector>#include<stack>using namespace std;const int M=105;int dp[M][M*5],n,m;#define vec vector<int>#define pb push_backvec G[M],edge[M];int wvf[M][3];int sccid[M],pre[M],lowlink[M],allc,dfs_clock;int w[M],val[M],fa[M];stack<int>stk;inline void Min(int &a,int b){if(a>b)a=b;}bool flag[M];bool predfs(int v){    pre[v]=lowlink[v]=++dfs_clock;    stk.push(v);    flag[v]=1;    for(int i=0;i<edge[v].size();++i){        int to=edge[v][i];        if(!pre[to])predfs(to),Min(lowlink[v],lowlink[to]);        else if(!sccid[to])Min(lowlink[v],pre[to]);    }    if(lowlink[v]==pre[v]){        sccid[v]=++allc;        for(;!stk.empty();){            int k=stk.top();stk.pop();            sccid[k]=allc;            val[allc]+=wvf[k][1];            w[allc]+=wvf[k][0];            if(k==v)break;        }    }}bool mark[M][M];inline void Graph(){    for(int i=1;i<=n;++i){        int v=sccid[i];        for(int j=0;j<edge[i].size();++j){            int to=sccid[edge[i][j]];            if(to==v)continue;            if(!mark[v][to])G[v].pb(to),fa[to]=v;        }    }}inline void Max(int &a,int b){if(a<b)a=b;}void dfs(int v){    for(int i=0;i<G[v].size();++i)        dfs(G[v][i]);    int k=m-w[v];    for(int j=0;j<G[v].size();++j){        int to=G[v][j];        for(int i=k;i>=0;--i)            for(int l=i;~l;l--)                Max(dp[v][i],dp[v][l]+dp[to][i-l]);    }    for(int i=1;i<=k;++i)        Max(dp[v][i],dp[v][i-1]);    for(int i=k;i>=0;--i)        dp[v][i+w[v]]=dp[v][i]+val[v],dp[v][i]=0;}vec que;int ans[M*5];int main(){    scanf("%d %d",&n,&m);    for(int j=0;j<=2;++j)        for(int i=1;i<=n;++i){            scanf("%d",&wvf[i][j]);            if(j==2&&wvf[i][j])edge[wvf[i][j]].pb(i);        }    for(int i=1;i<=n;++i)        if(!flag[i])predfs(i);    Graph();    for(int i=1;i<=allc;++i)        if(!fa[i])que.pb(i),dfs(i);    for(int i=0;i<que.size();++i){        int v=que[i];        for(int k=m;~k;--k)            for(int j=k;~j;--j)                Max(ans[k],dp[v][j]+ans[k-j]);    }//WA?    int res=0;    for(int i=0;i<=m;++i)        Max(res,ans[i]);    printf("%d\n",res);    return 0;}

其实跑完强连通以后可以不用树形dp+分组背包,可以直接对节点进行讨论,进行一个类似01背包的dp,这样就可以在最后讨论的时候省掉一个n,况且代码长度也可以大大缩短

因为没有去想所以没想到也是很正常的事情

0 0
原创粉丝点击