HDU 4044 GeoDefense(树形dp+分组背包)

来源:互联网 发布:电脑查询快捷键软件 编辑:程序博客网 时间:2024/06/07 15:55

题意:给你一棵n个结点的树,1号结点为敌人基地,叶子结点为我方基地。我们可以在任意一个结点至多修建一门大炮,每个结点有k种大炮,每种大炮有花费值和伤害值。问在给你m元的基础上,我们一定可以打败敌人的最大值。

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4044

题解思路:首先这是很明显的树形dp,我们要求的是每个结点的最小攻击值中的最大值,才能确保敌人无论走哪条路我们都能将期击败。具体思路是两次dp,第一次dp找出在i结点还没选择大炮的情况下的最小防御值中的最大值(这里有点难理解,当初想了一个下午才勉强明白,自己太渣了),第二次dp在第一次dp基础上选择加入哪种大炮的防御值最大(明显的分组背包)。

附上自己写的ac代码:

#include <algorithm>#include <iostream>#include <cstring>#include <string>#include <queue>#include <stack>#include <list>#include <map>#include <set>#define For0(n) for(int i = 0; i < n; i++)#define For1(n) for(int i = 1; i <= n; i++)#define Forn_m(n,m) for(int i = n; i <= m; i++)#define ForN_m(n,m) for(int i = n; i < m; i++) #define MAX 1005#define INF 0x3fusing namespace std;int hp[MAX][205];int T, n, m;vector <int> vec[MAX];bool vis[MAX];int dp[MAX][205];void dfs(int root){bool flag = false;int num = vec[root].size();vis[root] = true;For0(num)if (!vis[vec[root][i]]){int a = vec[root][i];dfs(a);flag = true;int t;for (int k = m; k >= 0; k--)//第一次dp{t = 0;for (int j = 0; j <= k; j++)t = max(t, min(dp[root][k - j], dp[vec[root][i]][j]));dp[root][k] = t;}}if (!flag)//叶子结点{Forn_m(0, m)dp[root][i] = hp[root][i];return;}for (int k = m; k >= 0; k--)//第二次dpfor (int j = 0; j <= k; j++)dp[root][k] = max(dp[root][k], dp[root][k - j] + hp[root][j]);}int main(){int u, v;scanf("%d", &T);while (T--){For0(MAX)vec[i].clear();memset(vis, 0, sizeof(vis));memset(dp, INF, sizeof(dp));memset(hp, 0, sizeof(hp));scanf("%d", &n);Forn_m(2, n){scanf("%d%d", &u, &v);vec[u].push_back(v);vec[v].push_back(u);}scanf("%d", &m);int num, x, y;For1(n){scanf("%d", &num);for (int j = 0; j < num; j++){scanf("%d%d", &x, &y);hp[i][x] = max(hp[i][x], y);}}For1(n)for (int j = 1; j <= m; j++)hp[i][j] = max(hp[i][j], hp[i][j - 1]);dfs(1);printf("%d\n", dp[1][m]);}return 0;}


0 0
原创粉丝点击