您的位置:首页 > 其它

[bzoj2427][HAOI2010]软件安装(树形dp+tarjan)

2017-10-15 14:17 381 查看

题目:

我是超链接

题解:

话说我一开始竟然用背包,woc太愚蠢了,儿子的权值和价值虽然保证了,但是很有可能和ta的父亲权值加重,看来得标准树形dp呢

f[i][j]表示以i为根的子树代价为j的最大权值,双层循环:j为子树x分配到的代价,k为子树v1[i]分配到的代价

为什么要单独拎出来一个in呢?如果这些点没有一个出来当根节点,就必须都连上0这个根。不加in的话就没有根啦

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#define N 505
using namespace std;
int ww
,vv
,d
,f

,tot,nxt
,point
,v
,tot1,nxt1
,point1
,v1
;
bool vis
;
int tmp,dfn
,stack
,low
,nn,cnt,belong
,hw
,hv
,x
,y
,m,in
;
void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}
void addline1(int x,int y){++tot1; nxt1[tot1]=point1[x]; point1[x]=tot1; v1[tot1]=y;}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++nn; vis[x]=1; stack[++tmp]=x;
for (int i=point[x];i;i=nxt[i])
if (!dfn[v[i]])
{
tarjan(v[i],x);
low[x]=min(low[x],low[v[i]]);
}else if (vis[v[i]]) low[x]=min(low[x],dfn[v[i]]);
if (low[x]==dfn[x])
{
int now=0;cnt++;
while (now!=x)
{
now=stack[tmp--];
vis[now]=0;
belong[now]=cnt;
hw[cnt]+=ww[now];
hv[cnt]+=vv[now];
}
}
}
void treedp(int x)
{
for (int i=point1[x];i;i=nxt1[i])
{
treedp(v1[i]);
for (int j=m-hw[x];j>=0;j--)
for (int k=0;k<=j;k++)
f[x][j]=max(f[x][j],f[x][k]+f[v1[i]][j-k]);
}
for (int j=m;j>=0;j--)
if (j>=hw[x]) f[x][j]=f[x][j-hw[x]]+hv[x];
else f[x][j]=0;
}
int main()
{
int n,i,j;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) scanf("%d",&ww[i]);
for (i=1;i<=n;i++) scanf("%d",&vv[i]);
for (i=1;i<=n;i++)
{
scanf("%d",&x[i]);
y[i]=i;
addline(x[i],i);
}
for (i=1;i<=n;i++)
if (!dfn[i]) tarjan(i,0);
for (i=1;i<=n;i++)
if (x[i] && belong[x[i]]!=belong[y[i]]) addline1(belong[x[i]],belong[y[i]]),in[belong[y[i]]]++;

for (i=1;i<=cnt;i++)
if (!in[i]) addline1(0,i);
treedp(0);
printf("%d",f[0][m]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: