zoukankan      html  css  js  c++  java
  • P6326 Shopping

    题目

    P6326 Shopping

    分析

    首先发现很明显是树上多重背包。

    于是可以考虑设状态 (dp[x][i]) 表示(必选(x))和其子树连通块,且背包容量为 (i) 时的最大价值。

    直接单调队列 (dp) ,明显是 (O(n^2m))

    那么考虑优化,我们发现这里的难点无非就是要处理每一个点作为当前根,那么我们直接考虑点分治,然后根节点必选即可。

    同时,我们还是也可以考虑暴力枚举,因为这里没有强制在线,所以直接启发式合并也可以做到 (O(nmlogn))

    这里可以用二进制优化,好像还跑的快点,代码细节见这里

    代码

    这里是点分治做法。

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;bool f=false;char ch=getchar();
    	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    } 
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    #define ll long long
    const int N=1005,V=4005;
    int t,n,m,Ans;
    int head[N],nex[N],to[N],idx;
    inline void add(int u,int v){
    	nex[++idx]=head[u];
    	to[idx]=v;
    	head[u]=idx;
    	return ;
    }
    int w[N],c[N],d[N];
    int Root,FMax,siz[N],Size;
    bool vis[N];
    void GetRoot(int x,int fa){
    	siz[x]=1;int Max=0;
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==fa||vis[y]) continue;
    		GetRoot(y,x);siz[x]+=siz[y];
    		Max=max(Max,siz[y]);
    	}
    	Max=max(Max,Size-siz[x]);
    	if(Max<=FMax) FMax=Max,Root=x;
    	return ;
    }
    int dp[N][V];
    void DP(int x,int fa,int lim){
    	if(lim-c[x]<0) return ;
    	int num=d[x]-1;
    	const int v=lim-c[x];
    	for(int i=0;i<=v;i++) dp[x][i]=dp[fa][i]+w[x];
    	for(int i=0;(1<<i)<=num;i++){
    		const int tmp=(1<<i);
    		for(int j=v;j>=c[x]*tmp;j--) dp[x][j]=max(dp[x][j],dp[x][j-c[x]*tmp]+w[x]*tmp);
    		num-=tmp; 
    	}
    	if(num){
    		const int tmp=num;
    		for(int j=v;j>=c[x]*tmp;j--) dp[x][j]=max(dp[x][j],dp[x][j-c[x]*tmp]+w[x]*tmp);
    		num-=tmp;
    	}
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(y==fa||vis[y]) continue;
    		DP(y,x,v); 
    		for(int j=c[y];j<=v;j++) dp[x][j]=max(dp[x][j],dp[y][j-c[y]]);
    	}
    	return ;
    }
    void Update(int x,int fa){
    	DP(x,0,m);
    	for(int i=0;i<=m-c[x];i++) Ans=max(Ans,dp[x][i]);
    	return ;
    }
    void DFS(int x,int fa){
    	vis[x]=true;Update(x,fa);
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(vis[y]) continue;
    		Size=FMax=siz[y],Root=y,GetRoot(y,x),DFS(Root,x); 
    	}
    	vis[x]=false;
    	return ;
    }	 
    signed main(){
    	read(t);
    	while(t--){
    		read(n),read(m);
    		idx=0;Ans=0;
    		memset(head,0,sizeof(head));
    		for(int i=1;i<=n;i++) read(w[i]);
    		for(int i=1;i<=n;i++) read(c[i]);
    		for(int i=1;i<=n;i++) read(d[i]);
    		for(int i=1;i<n;i++){
    			int u,v;
    			read(u),read(v);
    			add(u,v),add(v,u);
    		}
    		Size=FMax=n,Root=0,GetRoot(1,0),DFS(Root,0); 
    		write(Ans),putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android 编程下 Eclipse 恢复被删除的文件
    Android 编程下背景图片适配工具类
    Android 编程下 Managing Your App's Memory
    Android 编程下代码之(QQ消息列表滑动删除)
    Android 编程下 Canvas and Drawables
    Android 编程下 AlarmManager
    Android 编程下去除 ListView 上下边界蓝色或黄色阴影
    Java 编程下字符串的 16 位、32位 MD5 加密
    C#枚举类型和int类型相互转换
    MVC和普通三层架构的区别
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14728566.html
Copyright © 2011-2022 走看看