Luogu P2515
这道题的题面与P2146有点像。一些不同地方就是P2146是无环的,这题是有环的。
很显然,如果有几个软件的依赖关系形成环,那么这几个软件就可以被看成是一个大软件,其价值和空间都是原先的总和。
那么,我们就可以利用Tarjan算法求强连通分量+缩点,最后加一个树上的背包就可以了。
注意,缩点后的图不一定是一棵树,但是我们可以人为的加入一个权值为零的根节点,连接所有入度为0的点。
有关Tarjan算法和强连通分量:
【Luogu P3387】缩点模板(强连通分量Tarjan&拓扑排序)
#include<iostream> #include<cstdio> #include<queue> using namespace std; const int maxn=110,maxm=510; int dfn[maxn],low[maxn],stk[maxn],cnt,tim,d[maxn],tot,sccw[maxn],sccv[maxn]; int w[maxn],v[maxn],scc[maxn],in[maxn],ohead[maxn],ocnt,m,n,head[maxn],dp[maxn][maxm],ans; struct data { int to,next; }oe[maxn],e[maxn]; bool vis[maxn]; void Tarjan(int now) { dfn[now]=low[now]=++tim; stk[++cnt]=now; vis[now]=true; for (int i=head[now];i;i=e[i].next) { if (!dfn[e[i].to]) { Tarjan(e[i].to); low[now]=min(low[now],low[e[i].to]); } else { if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); } } if (dfn[now]==low[now]) { tot++; while (true) { scc[stk[cnt]]=tot; sccv[tot]+=v[stk[cnt]]; sccw[tot]+=w[stk[cnt]]; vis[stk[cnt]]=false; cnt--; if (stk[cnt+1]==now) break; } } } void dfs(int now)//树上背包 { //基本思路如下:枚举子树能取的空间,再利用01背包的原理进行状态转移。 //还有一种方法可以把多叉树转化成二叉树,按照左儿子又兄弟的原则重新建树。实现起来比较麻烦,所以没写。 for (int i=sccw[now];i<=m;i++) dp[now][i]=sccv[now];//初始值 for (int i=ohead[now];i;i=oe[i].next) { int to=oe[i].to; dfs(to); for (int j=m-sccw[now];j>=0;j--) { for (int k=0;k<=j;k++) dp[now][j+sccw[now]]=max(dp[now][j+sccw[now]],dp[now][j+sccw[now]-k]+dp[to][k]); } } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&w[i]); for (int i=1;i<=n;i++) scanf("%d",&v[i]); for (int i=1;i<=n;i++) { scanf("%d",&d[i]); e[i].to=i; e[i].next=head[d[i]]; head[d[i]]=i; //注意建边的方向。 } cnt=0; for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i); ocnt=0; for (int i=1;i<=n;i++) for (int j=head[i];j;j=e[j].next) if (scc[i]!=scc[e[j].to]) { oe[++ocnt].to=scc[e[j].to]; oe[ocnt].next=ohead[scc[i]]; ohead[scc[i]]=ocnt; in[scc[e[j].to]]++;//统计入度 } tot++;//人为加入的根节点 for (int i=1;i<tot;i++) if (in[i]==0) { oe[++ocnt].to=i; oe[ocnt].next=ohead[tot]; ohead[tot]=ocnt;//连边。 } dfs(tot); printf("%d\n",dp[tot][m]); return 0; }