UVA 12452 Plants vs. Zombies HD SP 树形dp(水

题目链接:点击打开链接

题意:

给定n个点的树[0,n)

开始所有边都是无色。

有3种操作:

1、选一个点染其相连的边 花费100

2、选一个点染其相连的2条边 花费175

3、选一个点染其相连的所有边 花费500

问:

染完所有边的最小花费。边可以重复染,点只能被操作一次。

#include <string>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if(c=getchar(),c==EOF) return 0;
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}

using namespace std;
typedef long long ll;
const int N = 10100;
const ll inf = 1e10;
struct Edge{
	int to, nex;
}edge[N<<1];
int head[N], edgenum;
void add(int u, int v){
	Edge E = {v, head[u]};
	edge[edgenum] = E;
	head[u] = edgenum++;
}
void init(){memset(head, -1, sizeof head); edgenum = 0;}
int n;
ll dp[N][2];
/*
dp[i][0] : i的父边选了
dp[i][1] : i的父边不选

*/
void up(ll &x, const ll &y){
    if(y<x)x = y;
}
void dfs(int u, int fa){
	dp[u][0] = dp[u][1] = inf;
	bool isleaf = true;
	ll a[3]; memset(a, 0, sizeof a);
	for(int i = head[u]; ~i; i = edge[i].nex){
		int v = edge[i].to; if(v == fa)continue;
		dfs(v, u);
		a[0] += dp[v][0];
		a[1] += dp[v][1];
		a[2] += min(dp[v][0], dp[v][1]);
		isleaf = false;
	}
	if(isleaf)	{dp[u][0] = 100; dp[u][1] = 0;return; }
///////
    up(dp[u][0], a[0]+100);
    up(dp[u][0], a[2]+500);
    up(dp[u][1], a[0]);
	ll b[3]; b[0] = b[1] = inf;
	for(int i = head[u]; ~i; i = edge[i].nex){
		int v = edge[i].to; if(v == fa)continue;
		up(dp[u][0], a[0]-dp[v][0]+dp[v][1] + 175);
		b[2] = -dp[v][0]+dp[v][1];
		sort(b, b+3);
	}
	up(dp[u][1], a[0]+b[0]+b[1]+175);
}
void input(){
	init();
	rd(n);
	for(int i = 1, u, v; i < n; i++){
		rd(u); rd(v);
		add(u, v); add(v, u);
	}
}
int main() {
	int T;scanf("%d", &T);
	while(T--){
		input();
		dfs(0, 0);
	//	for(int i = 0; i < n; i++)printf("%d: %lld %lld\n", i, dp[i][0], dp[i][1]);
		printf("$%lld\n", min(dp[0][0], dp[0][1]));
	}
	return 0;
}
/*
99
10
0 1
0 2
3 2
2 4
3 5
3 6
3 7
3 8
3 9

6
0 1
0 2
0 3
3 4
4 5

7
0 1
1 2
2 3
2 4
2 5
5 6

5
0 1
0 2
0 3
3 4

5
0 1
0 2
0 3
0 4

7
0 1
0 2
0 3
0 4
0 5
0 6

7
0 1
0 2
1 3
3 4
5 2
5 6

*/
时间: 2024-10-12 18:56:41

UVA 12452 Plants vs. Zombies HD SP 树形dp(水的相关文章

uva 12452 Plants vs. Zombies HD SP (树DP)

Problem I: Plants vs. Zombies HD Super Pro Plants versus Zombies HD Super Pro is a game played not a grid, but on a connected graph G with no cycles (i.e., a tree). Zombies live on edges of the tree and chew through edges so that tree falls apart! Pl

URAL 1039 Anniversary Party 树形DP 水题

1039. Anniversary Party Time limit: 0.5 secondMemory limit: 8 MB Background The president of the Ural State University is going to make an 80'th Anniversary party. The university has a hierarchical structure of employees; that is, the supervisor rela

uva 1220 - Party at Hali-Bula 【入门树形dp】

题目:uva 1220 - Party at Hali-Bula 题意:一个公司员工要举行聚会,要求任意一个人不能和他的直接上司同时到场,一个员工只有一个支系上司,现在求最多有多少人到场,并且方案是否唯一 分析:分析发现是要求一个树的最大独立集.这里可以用树形dp解决. 定义dp[x][0]:表示在 i 点不选 i 点的以 x 为子树的最大独立集 而dp[x][1] 表示x到场的最大独立集 定义f [x][0]:表示以x为根且x点不选的子树是否唯一 ,f[x][1]表示以x为根且x选的子树是否唯

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

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

洛谷P1352 没有上司的舞会(树形DP水题)

题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数. 输入输出格式 输入格式: 第一行一个整数N.(1<=N<=6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri.(-128<=Ri

树形DP水题系列(1):FAR-FarmCraft [POI2014][luogu P3574]

题目 大意: 边权为1 使遍历树时到每个节点的时间加上点权的最大值最小 求这个最小的最大值 思路: 最优化问题 一眼树形DP 考虑状态设立 先直接以答案为状态 dp[u] 为遍历完以u为根的子树的答案 再考虑状态转移 dp[u]=MAX(dp[to]+1,siz+dp[to]);siz为枚举子树到以to为节点的子树时之前已遍历的总时间 很明显这个转移过来的dp值的最优化依赖于子树遍历的顺序 所以我们需要找到一种最优的子树遍历顺序来使每个子树得到最优的dp值来更新 我们通过观察可以发现 交换任意两

hdu1520Anniversary party 树形dp水题

/* dp[i][0]表示第i个人不去的时候能得到的最大值 dp[i][1]表示第i个人去的时候得到的最大值 状态转移方程: dp[i][0]+=max(dp[next][0],dp[next][1]) dp[i][1]+=dp[next][0] 其中next为其子节点 */ #include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std;

树形DP水题杂记

BZOJ1131: [POI2008]Sta 题意:给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大. 题解:记录每个点的深度,再根据根节点的深度和逐层推导出其他点的深度和. 我用的是BFS #include <stdio.h> #include <string.h> #include <iostream> #include <queue> using namespace std; typedef long long ll; int

几个树形dp

1.重建道路 树形dp基础题,f[i][j]表示在i这个点我和我的子树联通块大小为j最少砍几条边. 转移的时候,到下一个子树时上一个子树所有答案先++(此树直接砍掉不贡献答案),再继续dp. 注意更新答案时,如果不是跟答案还有+1(砍掉我和我父亲的),不然洛谷会挂四个点QAQ 马上就Noip了我还只能做这种水题QAQ 还挂 //Twenty #include<algorithm> #include<iostream> #include<cstring> #include