标签:siz Shopping int big 4182 dfs Max dp BZOJ
题目
给定一棵大小为 \(n\) 的树,每个点代表一种物品,其具有体积、价值和数量的属性,
现在选择一个连通块,使得里面所有点都被选中且体积不超过 \(m\),问最大价值。
\(n\leq 500,m\leq 4000\)
分析
树形背包比较难维护,考虑用dfs序拍平到序列上,并且多重背包直接二进制拆分。
设 \(dp[i][j]\) 表示dfs序为 \(i\),且选择体积为 \(j\) 时能获得的最大价值。
如果不选这个点,那么 \(dp[i][j]=dp[rfn[i]][j]\),\(rfn\) 表示这个点的下一个兄弟的dfs序
如果选择这个点,那么 \(dp[i][j]=\max\{dp[i+1][j-w]+c\}\)
但有一个问题就是这样会变成01背包,考虑先用上式更新一次(强制必选一个),再用 \(dp[i][j-w]\) 更新。
就是在二进制拆分时先拆一个再正常拆,发现这样根节点强制必选,那么跑点分治,所有连通块都能被以当前根节点的情况所表示。
可以通过二进制拆分的个数来决定点的大小求带权重心,这样时间复杂度为 \(O(Tnm\log n\log m)\)
代码
#include <cstdio>
#include <cctype>
using namespace std;
const int N=511; struct node{int y,next;}e[N<<1]; struct rec{int w,c;}a[N<<3];
int siz[N],big[N],as[N],L[N],R[N],w[N],c[N],ans,root,tot,v[N],dfn[N],nfd[N],rfn[N],et=1,n,m,k,dp[N][N<<3];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void Max(int &x,int y){x=x>y?x:y;}
void dfs(int x,int fa){
siz[x]=R[x]-L[x]+1,big[x]=0;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y]){
dfs(e[i].y,x),siz[x]+=siz[e[i].y];
Max(big[x],siz[e[i].y]);
}
Max(big[x],big[0]-siz[x]);
if (big[x]<=big[root]) root=x;
}
void calc(int x,int fa){
dfn[x]=++tot,nfd[tot]=x;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y])
calc(e[i].y,x);
rfn[x]=tot+1;
}
void Dp(int x){
v[x]=1,tot=0,calc(x,0);
for (int i=0;i<=k;++i) dp[tot+1][i]=0;
for (int i=tot;i;--i){
int x=nfd[i];
for (int j=0;j<=k;++j) dp[i][j]=dp[rfn[x]][j];
for (int j=k;j>=w[x];--j)
Max(dp[i][j],dp[i+1][j-w[x]]+c[x]);
for (int o=R[x];o>L[x];--o)
for (int j=k;j>=a[o].w;--j)
Max(dp[i][j],dp[i][j-a[o].w]+a[o].c);
}
Max(ans,dp[1][k]);
for (int i=as[x];i;i=e[i].next)
if (!v[e[i].y]){
big[0]=siz[e[i].y];
dfs(e[i].y,root=0),Dp(root);
}
}
int main(){
for (int T=iut();T;--T){
n=iut(),k=iut(),ans=m=0,et=1;
for (int i=1;i<=n;++i) c[i]=iut();
for (int i=1;i<=n;++i) w[i]=iut();
for (int i=1;i<=n;++i){
int x=iut(); L[i]=R[i-1]+1;
a[++m]=(rec){w[i],c[i]},--x;
for (int t=1;x>=t;x-=t,t<<=1)
a[++m]=(rec){w[i]*t,c[i]*t};
if (x) a[++m]=(rec){w[i]*x,c[i]*x};
R[i]=m;
}
for (int i=1;i<n;++i){
int x=iut(),y=iut();
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
big[0]=m,dfs(1,root=0),Dp(root);
print(ans),putchar(10);
for (int i=1;i<=n;++i) v[i]=as[i]=0;
}
return 0;
}
标签:siz,Shopping,int,big,4182,dfs,Max,dp,BZOJ 来源: https://www.cnblogs.com/Spare-No-Effort/p/16031248.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。