您的位置:首页 > 其它

BZOJ 2427: [HAOI2010]软件安装

2016-06-26 16:36 357 查看
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_back
vec 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,况且代码长度也可以大大缩短

因为没有去想所以没想到也是很正常的事情
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息