[BZOJ2427][HAOI2010]软件安装(tarjan+树形DP)
如果依赖关系出现环,那么对于一个环里的点,要么都选要么都不选,
所以每个环可以当成一个点,也就是强连通分量
然后就可以构造出一颗树,然后树形背包瞎搞一下就行了
注意要搞一个虚拟节点当根节点
Code
#include <cstdio> #include <algorithm> #include <cstring> #define N 2010 using namespace std; struct info{int to,nex;}e[N],ne[N]; int n,m,w[N],v[N],tot,head[N],d[N],in[N]; int dfn[N],low[N],scc,tp,sta[N],bl[N],wei[N],val[N],dp[N][N]; bool inq[N]; void Link(int u,int v){ e[++tot].nex=head[u];head[u]=tot;e[tot].to=v; } inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void tarjan(int u){ dfn[u]=low[u]=++tot; sta[++tp]=u,inq[u]=1; for(int i=head[u],v;i;i=e[i].nex) if(!dfn[v=e[i].to]) tarjan(v),low[u]=min(low[u],low[v]); else if(inq[v]) low[u]=min(low[u],dfn[v]); if(dfn[u]==low[u]){ ++scc; for(int v=0;v!=u;)inq[v=sta[tp--]]=0,bl[v]=scc; } } void DP(int u){ for(int i=wei[u];i<=m;++i) dp[u][i]=val[u]; for(int i=head[u],v;i;i=e[i].nex){ DP(v=e[i].to); for(int j=m-wei[u];j>=0;--j) for(int k=0;k<=j;++k) dp[u][j+wei[u]]=max(dp[u][j+wei[u]],dp[u][j+wei[u]-k]+dp[v][k]); } } int main(){ n=read(),m=read(); for(int i=1;i<=n;w[i++]=read()); for(int i=1;i<=n;v[i++]=read()); for(int i=1;i<=n;++i) if(d[i]=read()) Link(d[i],i); tot=0; for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); tot=0,memset(head,0,sizeof(head)),memset(e,0,sizeof(e)); for(int i=1;i<=n;++i){ wei[bl[i]]+=w[i],val[bl[i]]+=v[i]; if(bl[i]!=bl[d[i]]&&d[i]) Link(bl[d[i]],bl[i]),in[bl[i]]++; } ++scc; for(int i=1;i<scc;++i) if(!in[i]) Link(scc,i); DP(scc); printf("%d\n",dp[scc][m]); return 0; }