UVALive 4015 Caves 树形背包

题目链接:点击打开链接

题意:

给定n个点的有根树(0为根),

下面给出边和边权

一个整数q表示q个询问

每个询问一个数字x ,表示有一个人从根开始走,行走距离不超过x且使得走过不相同的点最多。

问最多能走多少个点。

思路:

dp[i][j][0]表示以i为根的子树,以i为起点走了j个不同点且回到i的最小花费。

dp[i][j][1]表示不需要回到i的最小花费。

转移的时候就是一个背包

import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Queue;

public class Main {
	int n, q;
	int[] siz = new int[N];
	int[][][] dp = new int[N][N][2];//dp[i][j][0]表示以i为子树 走了j个点后回到i的最小花费,1表示不回到i
	int[][] tmp = new int[N][2];
	void input(){
		init_edge();
		for(int i = 1, u, v, dis; i < n; i++){
			u = cin.nextInt(); v = cin.nextInt(); dis = cin.nextInt();
			add(u, v, dis);
			add(v, u, dis);
		}
		q = cin.nextInt();
	}
	void dfs(int u, int fa){
		dp[u][1][0] = dp[u][1][1] = 0;
		siz[u] = 1;

		for(int i = head[u]; i != -1; i = edge[i].nex){
			int v = edge[i].to; if(v == fa)continue;
			dfs(v, u);
			siz[u] += siz[v];

			for(int j = siz[u]; j > 1; j--){
				for(int k = 1; k <= siz[v] && j-k>=0; k++)
				{
					dp[u][j][0] = min(dp[u][j][0], dp[u][j-k][0]+dp[v][k][0]+edge[i].dis*2);
					dp[u][j][1] = min(dp[u][j][1], dp[u][j-k][0]+dp[v][k][1]+edge[i].dis);
					dp[u][j][1] = min(dp[u][j][1], dp[u][j-k][1]+dp[v][k][0]+edge[i].dis*2);
				}
			}
		}
//		out.print(u+" back:");	for(int i = 1; i <= siz[u]; i++)out.print(dp[u][i][0]+ " "); out.println();out.print(u+" not back:");	for(int i = 1; i <= siz[u]; i++)out.print(dp[u][i][1]+ " "); out.println();
	}
	void work() {
		int Cas = 1;
		while(true){
			n = cin.nextInt(); if(n == 0)break;
			input();
			for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++)dp[i][j][0] = dp[i][j][1] = inf;
			dfs(0, 0);
			out.println("Case "+(Cas++)+":");
			while(q-->0){
				int x = cin.nextInt(), ans = 1;
				for(int i = 2; i <= n; i++)
					if(x>=dp[0][i][1])
						ans = i;
				out.println(ans);
			}
		}
	}

	Main() {
		cin = new Scanner(System.in);
		out = new PrintWriter(System.out);
	}

	public static void main(String[] args) {
		Main e = new Main();
		e.work();
		out.close();
	}

	public Scanner cin;
	public static PrintWriter out;
	static int N = 505;
	static int M = 505;
	DecimalFormat df=new DecimalFormat("0.0000");
	static int inf = (int) 1e9 + 7;
	static long inf64 = (long) 1e18;
	static double eps = 1e-8;
	static int mod = 1000000007 ;

	class Edge{
		int from, to, dis, nex;
		Edge(){}
		Edge(int from, int to, int dis, int nex){
			this.from = from;
			this.to = to;
			this.dis = dis;
			this.nex = nex;
		}
	}
	Edge[] edge = new Edge[M<<1];
	int[] head = new int[N];
	int edgenum;
	void init_edge(){for(int i = 0; i < N; i++)head[i] = -1; edgenum = 0;}
	void add(int u, int v, int dis){
		edge[edgenum] = new Edge(u, v, dis, head[u]);
		head[u] = edgenum++;
	}/*
	int upper_bound(int[] A, int l, int r, int val) {// upper_bound(A+l,A+r,val)-A;
		int pos = r;
		r--;
		while (l <= r) {
			int mid = (l + r) >> 1;
			if (A[mid] <= val) {
				l = mid + 1;
			} else {
				pos = mid;
				r = mid - 1;
			}
		}
		return pos;
	}/**/

	int Pow(int x, int y) {
		int ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			y >>= 1;
			x = x * x;
		}
		return ans;
	}
	double Pow(double x, int y) {
		double ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			y >>= 1;
			x = x * x;
		}
		return ans;
	}
	int Pow_Mod(int x, int y, int mod) {
		int ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			ans %= mod;
			y >>= 1;
			x = x * x;
			x %= mod;
		}
		return ans;
	}

	long Pow(long x, long y) {
		long ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			y >>= 1;
			x = x * x;
		}
		return ans;
	}

	long Pow_Mod(long x, long y, long mod) {
		long ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			ans %= mod;
			y >>= 1;
			x = x * x;
			x %= mod;
		}
		return ans;
	}

	int gcd(int x, int y){
		if(x>y){int tmp = x; x = y; y = tmp;}
		while(x>0){
			y %= x;
			int tmp = x; x = y; y = tmp;
		}
		return y;
	}
	int max(int x, int y) {
		return x > y ? x : y;
	}

	int min(int x, int y) {
		return x < y ? x : y;
	}

	double max(double x, double y) {
		return x > y ? x : y;
	}

	double min(double x, double y) {
		return x < y ? x : y;
	}

	long max(long x, long y) {
		return x > y ? x : y;
	}

	long min(long x, long y) {
		return x < y ? x : y;
	}

	int abs(int x) {
		return x > 0 ? x : -x;
	}

	double abs(double x) {
		return x > 0 ? x : -x;
	}

	long abs(long x) {
		return x > 0 ? x : -x;
	}

	boolean zero(double x) {
		return abs(x) < eps;
	}
}
时间: 2024-10-12 02:37:52

UVALive 4015 Caves 树形背包的相关文章

UVALive 4015 - Caves(树形DP)

Description It is said that the people of Menggol lived in caves. A tribe's caves were connected to each other with paths. The paths were so designed that there was one and only one path to each cave. So the caves and the paths formed a tree. There w

UVa 1407 树形背包 Caves

这道题可以和POJ 2486 树形背包DP Apple Tree比较着来做. 参考题解 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 500 + 10; 9 10 int n, Q; 11 vec

hdu1561:树形背包dp

给定n个地点,每个地点藏有cost[i]的宝物,取得某些宝物有时需要先取其他宝物,现在让我们选m个地点问最多可以选多少宝物? 还是挺裸的树形背包dp吧,不难,关键还是中间dp的部分.可以做模板了->_-> 注意点:多组数据的话如果第一组对了然后其他都错了,那么很有可能是初始化的时候漏了.这次找可很久才知道差了e[0].clear().平时的习惯都是从1开始. --------------------------------------------------------------------

POJ 1155 树形背包

题意:从一个发射站发射电视,只有叶子节点是用户,收到一部分费用,所有的边都有花费,求在不亏本的情况下,最多可以让多少用户(叶子结点)收看到电视. 分析:树形背包. 状态定义: dp(i,j) : 以 i 为根的,让 j 个用户看到电视,最大获益(可以为负数).那么sz不再是原来的定义了. 最后遍历 j,第一个不为负数的就是答案. 状态转移:树形背包,dp(i,j) = max(d(i,j) , dp(i)(k)+dp(son,j-k)-w); #include <algorithm> #inc

【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包

[BZOJ2427][HAOI2010]软件安装 Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大).但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0.我们现在知道

【bzoj4987】Tree 树形背包dp

题目描述 从前有棵树. 找出K个点A1,A2,…,Ak. 使得∑dis(AiAi+1),(1<=i<=K-1)最小. 输入 第一行两个正整数n,k,表示数的顶点数和需要选出的点个数. 接下来n-l行每行3个非负整数x,y,z,表示从存在一条从x到y权值为z的边. I<=k<=n. l<x,y<=n 1<=z<=10^5 n <= 3000 输出 一行一个整数,表示最小的距离和. 样例输入 10 7 1 2 35129 2 3 42976 3 4 244

NYOJ 674 善良的国王(树形背包DP)

善良的国王 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 传说中有一个善良的国王Good,他为了不劳民伤财,每当建造一个城镇的时候都只用一条路去连接,这样就可以省很多的人力和物力,也就说如果有n个城镇,那么只需要n-1条路就可以把所有的城镇链接起来了(也就是一颗树了).但是不幸的事情发生了:有个一强大的帝国想要占领这个国家,但是由于国王Good的兵力不足,只能守护m个城镇,所以经过商量,国王Good只能从他的所有城镇中选择m个相链接的城市,并且把所有可以链接到这m

【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp

题目描述 JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一位编号比他小的候选人Ri推荐.如果Ri=0则说明这个候选人是JYY自己看上的.为了保证团队的和谐,JYY需要保证,如果招募了候选人i,那么候选人Ri"也一定需要在团队中.当然了,JYY自己总是在团队里的.每一个候选人都有一个战斗值Pi",也有一个招募费用Si".JYY希望招募K个候选人(JYY自己不算),组成一个性价比最高的团队.也就是,这K个被JYY选择的候

poj2486Apple Tree[树形背包!!!]

Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9989   Accepted: 3324 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amoun