1. 程式人生 > >JZOJ4202. Shopping(點分治+樹形依賴+多重揹包)

JZOJ4202. Shopping(點分治+樹形依賴+多重揹包)

題意:

  • 一顆樹,每個點代表一個物品,空間c[i],數量d[i],價值w[i],現有一個空間為m的揹包,選樹上相互連線的物品,求最大價值

想法:

  • 一眼樹形揹包,時間複雜度上天
  • f[i][j]表示i的子樹內,i必選一個,空間為j的最大價值
  • 時間複雜度O(n2m2d
  • 由於選互相連線的物品,所以我們可以假定必須選某個點,然後做一次樹形依賴多重揹包,最後在遞迴到子樹內繼續找
  • 那肯定是找樹的重心啊,所以遞迴成點分治
  • 樹形依賴:由於要選某個點必須要選他的所有祖先,所以可以先做出dfn
  • i=dfn[x]
  • 選:f[i+1][y]=max(f[i+1][y],f[i][yc[x]]+w[x])
  • 不選:f[i+siz[x]+1][y]=max(f[i+siz[x]+1][y],f[i][y])
  • 多重揹包
  • 選d個的話
  • 把它分成1+2+4+,,,,,+2n+y的形式,當01揹包做,每個物品即空間c[i]2n,價格w[i]2n
  • 好像還有一種單調佇列的套路,找機會學一學
    -時間複雜度(
    nlognmlogd
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define fb(i,x) for(i=last[x];i;i=next[i]) 
const int maxN=510,maxM=4010,maxn=-1e9; using namespace std; bool bz[maxN],broke[maxN]; int t,n,m,tot,i,w[maxN],c[maxN],d[maxN],f[maxN][maxM],last[maxN], tov[maxN*2],next[maxN*2],pre[maxN],h[maxM],cnt,siz[maxN], ans,x,y,cm[maxN],fa[maxN]; void insert(int x,int y){ tov[++tot]=y,next[tot]=last[x],last[x]=tot; } void dfss(int x){ int i,y; bz[x]=true,pre[++cnt]=x,siz[x]=1; fb(i,x){ y=tov[i]; if (!bz[y] && !broke[y]) dfss(y),siz[x]+=siz[y],fa[y]=x; } } void find_ans(){ int x,i,j,xx,yy,k; fo(i,1,cnt+1) fo(j,0,m) f[i][j]=maxn; f[1][0]=0; fo(i,1,cnt){ x=pre[i]; fo(j,0,m) h[j]=maxn; fo(j,c[x],m) if (f[i][j-c[x]]!=maxn)h[j]=f[i][j-c[x]]+w[x]; y=d[x]-1; fo (j,0,7){ if (y<cm[j]) break; xx=cm[j]*w[x],yy=cm[j]*c[x]; fd(k,m,yy) if (h[k-yy]!=maxn) h[k]=max(h[k],h[k-yy]+xx); y-=cm[j]; } xx=y*w[x],yy=y*c[x]; fd(j,m,yy) if (h[j-yy]!=maxn) h[j]=max(h[j],h[j-yy]+xx); fo(j,c[x],m) f[i+1][j]=max(f[i+1][j],h[j]); fo(j,0,m) f[i+siz[x]][j]=max(f[i+siz[x]][j],f[i][j]); } fo(i,0,m) ans=max(ans,f[cnt+1][i]); } void dfs(int x){ int j,cut=0,yy,i; bool bz1; cnt=0,dfss(x); fo(i,1,cnt){ yy=pre[i],bz1=true; if (cnt-siz[yy]>cnt/2) continue; fb(j,yy) if (siz[tov[j]]>cnt/2 && tov[j]!=fa[yy] && !broke[tov[j]]) {bz1=false; break; } if (bz1){ cut=yy; break; } } broke[cut]=true; fo(i,1,cnt) siz[pre[i]]=0,bz[pre[i]]=false,fa[pre[i]]=0; cnt=0,dfss(cut); find_ans(); fo(i,1,cnt) siz[pre[i]]=0,bz[pre[i]]=false,fa[pre[i]]=0; fb(i,cut){ yy=tov[i]; if (!broke[yy]) dfs(yy); } } int main(){ freopen("shopping.in","r",stdin); freopen("shopping.out","w",stdout); cm[0]=1; fo(i,1,7) cm[i]=cm[i-1]*2; for (scanf("%d",&t);t;t--){ mem(last,0),mem(bz,false),mem(broke,false),tot=0; scanf("%d%d",&n,&m); fo(i,1,n) scanf("%d",&w[i]); fo(i,1,n) scanf("%d",&c[i]); fo(i,1,n) scanf("%d",&d[i]); fo(i,1,n-1) scanf("%d%d",&x,&y),insert(x,y),insert(y,x); ans=0; dfs(1); printf("%d\n",ans); } }