hdu 5290 Bombing plan(树形dp)

题目链接:hdu 5290 Bombing plan

dpDestroy[u][i]表示以u为根节点的子树全部被摧毁,并且向上还可以破坏到距离u为i的城市;dpSafe[u][i]表示以u为根节点的子树中有距离u深度为i的城市还未被破坏。

dpDestroy[u][i] = dpDestroy[v][i+1] + sum{ min(dpDestroy[k][j], dpSafe[k][j])(j≤i)| k为除了v以外的子节点}

dpSafe[u][i] = dpSafe[v][i-1] + sum{ min(dpSafe[k][j], dpDestroy[k][j]) (j≤i)| k为除了v以外的子节点}

然后在转移一下u节点放炸弹的情况,这样的直接做的复杂度是o(n * w * w)

对于每个节点,可以维护一个前缀最小值,加速查询,minDestroy[u][i] = min{ dpDestroy[u][j] (j≤i)}

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
const int maxn = 1e5 + 5;
const int maxm = 100;
const int inf = 0x3f3f3f3f;

int N, W[maxn], dpDestroy[maxn][maxm + 5], dpSafe[maxn][maxm + 5];
int minDestroy[maxn][maxm + 5], minSafe[maxn][maxm + 5];
vector<int> G[maxn];

void init () {
	for (int i = 1; i <= N; i++) {
		scanf("%d", &W[i]);
		G[i].clear();
	}

	int u, v;
	for (int i = 1; i < N; i++) {
		scanf("%d%d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
}

void dfs (int u, int f) {
	for (int i = 0; i <= maxm; i++)
		dpDestroy[u][i] = dpSafe[u][i] = N;

	int tmp = 0;
	for (int i = 0; i < G[u].size(); i++) {
		int v = G[u][i];
		if (v == f)
			continue;

		dfs(v, u);
		tmp += min(minDestroy[v][W[u]], (W[u] ? minSafe[v][W[u]-1] : inf));
	}
	dpDestroy[u][W[u]] = tmp + 1;

	for (int i = 0; i < maxm; i++) {
		int p = 0, q = 0;
		for (int j = 0; j < G[u].size(); j++) {
			int v = G[u][j];
			if (v == f)
				continue;
			p += min(minDestroy[v][i + 1], (i == 0 ? inf : minSafe[v][i-1]));
			q += min(minDestroy[v][i], (i == 0 ? inf : minSafe[v][i-1]));
		}

		for (int j = 0; j < G[u].size(); j++) {
			int v = G[u][j];
			if (v == f)
				continue;
			//dpDestroy[u][i] = min(dpDestroy[u][i], p+dpDestroy[v][i+1]-min(minDestroy[v][i+1], minSafe[v][i]));
			if (i)  {
				dpDestroy[u][i] = min(dpDestroy[u][i], p+dpDestroy[v][i+1]-min(minDestroy[v][i+1], minSafe[v][i-1]));
				dpSafe[u][i] = min(dpSafe[u][i], q + dpSafe[v][i-1] - min(minDestroy[v][i], minSafe[v][i-1]));
			} else {
				dpDestroy[u][i] = min(dpDestroy[u][i], p+dpDestroy[v][i+1]-min(minDestroy[v][i+1], inf));
				dpSafe[u][i] = min(dpSafe[u][i], q);
			}
		}
	}

	if (G[u].size() == 1)
		dpSafe[u][0] = 0;

	minDestroy[u][0] = dpDestroy[u][0];
	minSafe[u][0] = dpSafe[u][0];
	for (int i = 1; i <= maxm; i++) {
		minDestroy[u][i] = min(minDestroy[u][i-1], dpDestroy[u][i]);
		minSafe[u][i] = min(minSafe[u][i-1], dpSafe[u][i]);
	}
}

int main () {
	while (scanf("%d", &N) == 1) {
		init();
		dfs(1, 0);
		printf("%d\n", minDestroy[1][maxm]);
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-22 16:05:58

hdu 5290 Bombing plan(树形dp)的相关文章

HDU 5290 Bombing plan 树形dp

题目链接 题意 给定n个点的树,每个点有一个点权wi, 每次选一个点u,则树上u和距离u wi范围内的所有点都会被染色. 问:最少选几个点使得n个点都被染色. 思路:树形dp 对于某个点u down[u][j] 表示u以及u向下深度为 j 的点没有被染色的最小花费. up[u][j] 表示u以及u向上距离为j的点已经被染色的最小花费. 设u点的儿子们为v, v2, v3 ···,每个点点权为w[]数组 3种转移: 1.对于down[u][i] 显然就是子树的down数组求和,特殊一点就是down

HDU 5290 Bombing plan

题意 X国有n(n<105)个城市,用n-1条无向边连接.城市i有一个权值wi(wi<100),如果炸毁城市i,那么距离i不超过wi的节点也会被炸毁.求炸毁所有城市最少需要炸几次. Solution 相比前几天做的SGU 280 不同之处在与这题对每个点有不同的k. 但这一题不能贪心,只能采用dp的方法.形式上却也差不多,都是对子树的讨论.令f[i][j]为以i为根的子树,能向子树外拓展i个节点最少需要炸毁几个城市.G[i][j]为以i为根的子树,子树内有节点未被炸毁,且距离根为j最少需要炸毁

HDU 1011 Starship Troopers(树形DP)

Starship Troopers Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submission(s) : 62   Accepted Submission(s) : 12 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description You, the leader of

hdu 1520Anniversary party(简单树形dp)

Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4310    Accepted Submission(s): 1976 Problem Description There is going to be a party to celebrate the 80-th Anniversary of the

hdu 4044 GeoDefense (树形dp+01背包)

GeoDefense Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 663    Accepted Submission(s): 267 Problem Description Tower defense is a kind of real-time strategy computer games. The goal of towe

HDU 2196 Computer 经典树形DP

一开始看错题了,后来发现原来是在一颗带权的树上面求出距离每一个点的最长距离,做两次dfs就好,具体的看注释? #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #incl

hdu 5452 Minimum Cut 树形dp

Minimum Cut Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5452 Description Given a simple unweighted graph G (an undirected graph containing no loops nor multiple edges) with n nodes and m edges. Let T be a spa

HDU 2376 Average distance (树形dp)

Average distance Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 588    Accepted Submission(s): 213 Special Judge Problem Description Given a tree, calculate the average distance between two ve

POJ 2342 &amp;&amp;HDU 1520 Anniversary party 树形DP 水题

一个公司的职员是分级制度的,所有员工刚好是一个树形结构,现在公司要举办一个聚会,邀请部分职员来参加. 要求: 1.为了聚会有趣,若邀请了一个职员,则该职员的直接上级(即父节点)和直接下级(即儿子节点)都不能被邀请 2.每一个员工都有一个兴奋值,在满足1的条件下,要使得邀请来的员工的兴奋值最高 输出最高的兴奋值. 简单的树形DP dp[i][1]:表示以i为根的子树,邀请节点i的最大兴奋值 dp[i][0]:表示以i为根的子树,不邀请节点i的最大兴奋值 先根据入度找出整棵树的根节点, 然后一次DF