[HAOI2010]软件安装
Posted qjs12
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2010]软件安装相关的知识,希望对你有一定的参考价值。
网上对这题一致好评,然而像我这种没见过世面的,不知道什么是好题,什么题不好......
数据会出现环形依赖关系,环形里面的软件选一个就要全选,相当于一件物品。
所以先跑Tarjan,把强连通分量缩成一个点,之后按强连通分量建图,原图 u->v,新边 scc[v]->scc[u],表示安装scc[v]以后才能装scc[u]。
之后是树形背包。
这是我的第一道树形背包。(我的题解顺序不代表写题顺序,我的题解是补得)
很没有经验。
第一次是按我自己简单的思路走的,只得了30。
原因是在子树空间分配上出了问题,导致在我的dfs过程中丢失了很多状态。
f[u][j] 表示给以 u 为根的子树分配 j 空间的最优值。
要枚举每一个状态。
第一维要枚举 j,第二维枚举 k,意义在于:当以 u 为根的子树有 j 空间时,给 u 的子树 v 分配 j-k 空间。
f[u][j] = max ( f[u][j] , f[u][k] + f[v][j-k] )
上述过程并没有把根节点的贡献算进去。
所以之后要一边循环把根节点的贡献算上。
当状态成立当且仅当 f[u][j] 的 j>=w[u],此时 f[u][j] = f[u-w[u]] + val[u] 。
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<stack> using namespace std; const int N=100+10,M=500+10; int n,m,_weight[N],weight[N],_value[N],value[N],f[N][M],cnt,head[N]; struct Edge { int u,v,nex; Edge():u(0),v(0),nex(-1) {} }ed[N]; void add_edge(int a,int b) { ed[++cnt].u=a,ed[cnt].v=b,ed[cnt].nex=head[a],head[a]=cnt; } int dfs_clock,scc_cnt,pre[N],low[N],idx[N],in[N],g[N][N]; stack<int> s; void find_scc(int u) { pre[u]=low[u]=++dfs_clock; s.push(u); for(int i=head[u];i!=-1;i=ed[i].nex) { Edge e=ed[i]; if(!pre[e.v]) { find_scc(e.v); low[u]=min(low[u],low[e.v]); }else if(!idx[e.v]) low[u]=min(low[u],pre[e.v]); } if(low[u]==pre[u]) { ++scc_cnt; for(;;) { int v=s.top(); s.pop(); idx[v]=scc_cnt; if(v==u) break; } } } void dfs(int u) { // f[u][k]给以u为根的子树分配k空间的最优值(含根). for(int i=1;i<=scc_cnt;i++) if(g[u][i]) { dfs(i); for(int j=m;j>=0;j--) // 这两个循环相当于给u的子树分配空间. for(int k=0;k<=j;k++) f[u][j]=max(f[u][j],f[u][k]+f[i][j-k]); } for(int j=m;j>=0;j--) { // 在这一步把当前节点(即根节点)的贡献加进去. if(j>=weight[u]) f[u][j]=f[u][j-weight[u]]+value[u]; else f[u][j]=0; } } void input() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); int x; for(int i=1;i<=n;i++) scanf("%d",&_weight[i]); for(int i=1;i<=n;i++) scanf("%d",&_value[i]); for(int i=1;i<=n;i++) { scanf("%d",&x); if(x) add_edge(i,x); } } void prepare() { for(int i=1;i<=n;i++) if(!pre[i]) find_scc(i); for(int i=1;i<=n;i++) { weight[idx[i]]+=_weight[i]; value[idx[i]]+=_value[i]; for(int j=head[i];j!=-1;j=ed[i].nex) { Edge e=ed[j]; if(idx[e.u]!=idx[e.v]) { g[idx[e.v]][idx[e.u]]=true; in[idx[e.u]]++; } } } for(int i=1;i<=scc_cnt;i++) if(!in[i]) g[0][i]=true; } int main() { freopen("install.in","r",stdin); freopen("install.out","w",stdout); input(); prepare(); dfs(0); printf("%d\n",f[0][m]); return 0; }
以上是关于[HAOI2010]软件安装的主要内容,如果未能解决你的问题,请参考以下文章