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
其实跑完强连通以后可以不用树形dp+分组背包,可以直接对节点进行讨论,进行一个类似01背包的dp,这样就可以在最后讨论的时候省掉一个n,况且代码长度也可以大大缩短
因为没有去想所以没想到也是很正常的事情
现在我们的手头有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,况且代码长度也可以大大缩短
因为没有去想所以没想到也是很正常的事情
相关文章推荐
- BZOJ3275 Number (最小割)
- BZOJ2809——[Apio2012]dispatching
- BZOJ2809——[Apio2012]dispatching
- 树形DP 或 最小顶点覆盖=最大匹配(双向图)(HDU 1053)
- hdu 1712 ACboy needs your help (分组背包)
- [bzoj1003] [ZJOI2006]物流运输trans
- [bzoj1500][NOI2005]维修数列
- [bzoj1208] [HNOI2004]宠物收养所
- [bzoj1269][AHOI2006]文本编辑器editort
- [bzoj1503][NOI2004]郁闷的出纳员
- bzoj4305 数学
- bzoj3926 广义后缀自动机
- bzoj2780 广义后缀自动机+parent树+Dfs序+树状数组
- BZOJ1997 2-sat
- bzoj4027 贪心
- [BZOJ2038][2009国家集训队][莫队][分块]小z的袜子
- [BZOJ2594][WC2006][LCT][MST]水管局长数据加强版
- [BZOJ2300][HAOI2011][动态凸包]防线修建
- [BZOJ1045][HAOI2008][贪心]糖果传递
- [BZOJ2539][CTSC2000][KM]丘比特的烦恼