HDU 4044 GeoDefense(动态规划)

 

GeoDefense

 

Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 745    Accepted Submission(s): 307

 

 

Problem Description

 

 

Tower defense is a kind of real-time strategy computer games. The goal of tower defense games is to try to stop enemies from reaching your bases by building towers which shoot at them as they pass. 


The choice and positioning of the towers is the essential strategy of the game. Many games, such as Flash Element Tower Defense, feature enemies that run through a "maze", which allows the player to strategically place towers for optimal effectiveness. However, some versions of the genre force the user to create the maze out of their own towers, such as Desktop Tower Defense. Some versions are a hybrid of these two types, with preset paths that can be modified to some extent by tower placement, or towers that can be modified by path placement.

geoDefense is a Thinking Man’s Action Tower Defense. It has become one of "PC World's 10 iPhone Games You CANNOT Live Without". Using exciting vectorized graphics, this highly kinetic game brings a whole new dimension to the defense genre. Devastate creeps with blasters, lasers and missiles and watch their energy debris swirl through the gravity wells of your vortex towers.

There is a geoDefense maze of n points numbered from 1 and connected by passageways. There are at least two dead ends among these n points, and there is always one and only one path between any pair of points. Point 1 is a dead end, and it’s the base of enemies, and all the other dead ends are your bases.

To prevent the enemy reaching your bases, you have to construct towers to attack the enemy. You can build tower on any point and you can only build one tower on one point. A tower can only shot the enemy when it passes the tower. You are given ki choices to build tower on point i, and each choice is given in the format of (price, power) which means that you can build a tower with attack power value equals power in the cost of price. You can also build nothing on a point so it will not cost your money. A tower will reduce the enemy’s HP by its attack power. When the HP is less or equal to zero, the enemy dies immediately. 

The base of enemies will release only one enemy. It moves very fast that you cannot do anything such as building towers while it is running. It runs all the way until it dies or reaches one of your bases. However, you cannot predict the route it will go through. To win the game, you must kill the enemy before it reaches your bases. You have to strategically place towers for optimal effectiveness so that the fortifications are steady enough to protect the bold and powerful enemy with high HP. You are troubling your head on figuring out the highest HP of the enemy you are able to kill on the way certainly. You have money m when the game begins.
Please note that the towers build in the enemy’s base or your bases are all effective and if the enemy is shot to death in your bases, you still win.
 

 

Input

 

The input consists of several test cases. The first line is an integer T (1 <= T <= 20), which shows the number of the cases.
For each test case, the first line contains only one integer n (2 <= n <= 1000) meaning the number of points. 
The following n-1 lines describe the passageways. Each line contains two integers u and v, which are the endpoints of a passageway. 
The following line contains only one integer m (1 <= m <= 200) meaning the amount of your money when the game begins. 
Then n lines follow. The ith line describes the construction choices of the ith point. It starts with an integer ki (0 <= ki <= 50) and ki is followed by ki pairs of integers separated by spaces. The jth pair is (pricei,j, poweri,j), 0 <= pricei,j <= 200, 0 <= poweri,j <= 50000. ki being zero means that you can’t build a tower on the ith point. 
 

 

Output

 

For each test case, output a line containing the highest HP value of your enemy that you can deal with. It means that if your enemy’s HP is larger than that highest value, you can’t guarantee your victory.
 

 

Sample Input

 

 
2 2 1 2 30 3 10 20 20 40 30 50 3 10 30 20 40 30 45 4 2 1 3 1 1 4 60 3 10 20 20 40 30 50 3 10 30 20 40 30 45 3 10 30 20 40 30 35 3 10 30 20 40 30 35
 

 

Sample Output

 

 
70 80
 

 

Source

 

 

 

Recommend

 

lcy   |   We have carefully selected several similar problems for you:   4050  4042  4047  4048  4040 
 
 

 

题目输入描述:

有T组测试数据,每组

首先一个n,表示一颗生成树有n个节点

接下来n-1行表示n-1条边描述这个生成树

接下来一行表示你的总的钱数sum

接下来n行,第i行表示树上的第i号节点可以建 ki 个 塔,每个塔两个数字参数表示花费和造成的伤害。

这是个塔防游戏,敌人从树根(1号节点)出发,叶子节点是你的基地,敌人的路线不固定,经过每个节点的塔后受到伤害

问你在总的花费下,你选择建一些塔,敌人的血量至多是多少才能保证不伤害到你的基地。



解题思路:

 

这题已经讨论过,用两个DP,也就是DP里面套一个DP,今天思维清晰,实现了,代码100行,超过了正常DP的长度。

有人用树形DP去实现,不管用什么实现,核心思路肯定相像。

 

(1)首先,可以把这整颗树看成一个问题,就是让这个树要求的那个答案ans最大。

要使 ans 最大,就可以分析一下,我认为ans可以分成两部分

第一部分:这个很简单,就是“树根”造塔产生的花费ci,造成的伤害pi

第二部分:

这个比较复杂,就是树根下有很多子树,也就是敌人可能走任意一条路,很明显敌人会走哪个伤害最小的路。

也就是在剩下的钱数下使得最小的路径的伤害值最大,假设以求出,记为DP2([son],left_money)

综合这个两个部分,所以这颗树的答案ans=DP1(root,sum) = max { pi + DP2([son],sum-ci) }

 

(2)那么 DP2([son],money)这个怎么求?

这个也很好求,枚举每个son的花费,在所有的花费的情况下求最大,但是儿子之间的伤害取最小。

也就是:DP2([son],money)=DP2(son1,money)

假设第一个儿子花了Ci元,得到的伤害是多少呢?很明显示DP1(son1,Ci)

所以DP2(son1,money)= max{ min( DP1(son1,Ci),DP(son2,money-Ci) ) }

综上,由(1)(2)两个DP可以求出答案也就是调用DP1(1,sum).


解题代码:

 

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn=1100;

vector <int> g[maxn],path[maxn];
vector < pair<int,int> > v[maxn];
int n,money,next[maxn];
int dp1[maxn][210],dp2[maxn][210],vis1[maxn][210],vis2[maxn][210],mark1,mark2;

int DP1(int k,int sum);

int DP2(int k,int sum){
	if(k==-1) return (1<<30);
	if(vis2[k][sum]==mark2) return dp2[k][sum];
	int ans=0;
	for(int i=0;i<=sum;i++){
		int tmp=min(DP1(k,i),DP2(next[k],sum-i));
		if(tmp>ans) ans=tmp;
	}
	vis2[k][sum]=mark2;
	return dp2[k][sum]=ans;
}

int DP1(int k,int sum){
	if(vis1[k][sum]==mark1) return dp1[k][sum];
	int ans=0;
	for(int i=0;i<v[k].size();i++){
		if(sum<v[k][i].first) continue;
		int tmp=v[k][i].second;
		if(g[k].size()>0) tmp+=DP2(g[k][0],sum-v[k][i].first);
		if(tmp>ans) ans=tmp;
	}
	vis1[k][sum]=mark1;
	return dp1[k][sum]=ans;
}

void dfs(int u,int fa){
	for(int i=0;i<path[u].size();i++){
		if(path[u][i]!=fa){
		    g[u].push_back(path[u][i]);
		    dfs(path[u][i],u);
		}
	}
}

void init(){
	for(int i=0;i<=n;i++){
		g[i].clear();
		v[i].clear();
		path[i].clear();
	}
	mark1++;
	mark2++;
}

void input(){
	int x,y,q;
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		path[x].push_back(y);
		path[y].push_back(x);
	}
	scanf("%d",&money);
	for(int i=1;i<=n;i++){
		scanf("%d",&q);
		v[i].push_back(make_pair(0,0));
		while(q-- >0){
			scanf("%d%d",&x,&y);
			v[i].push_back(make_pair(x,y));
		}
	}
	dfs(1,-1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<g[i].size();j++){
			next[g[i][j-1]]=g[i][j];
		}
		if(g[i].size()>0) next[g[i].back()]=-1;
	}
}

void solve(){
	printf("%d\n",DP1(1,money));
}

int main(){
	int T;
	scanf("%d",&T);
	for(int t=0;t<T;t++){
		scanf("%d",&n);
		init();
		input();
		solve();
	}
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炒饭君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值