GeoDefense
Time Limit: 12000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 347 Accepted Submission(s): 138
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
The 36th ACM/ICPC Asia Regional Beijing Site —— Online Contest
Recommend lcy 题目看起来比较吓人啊~~~~
题目大意
:给定n个节点组成的树,1为敌方基地,叶子结点为我方结点。我们可以在每个结点安放炮台,至多一炮,然后就可以打炮,每个结点有ki种炮,每种炮有一个花费和一个能量(能量对应着打掉敌人多少hp)。敌人可能往一个结点的每条分支跑,所以要想保证守住阵地,就要保证每个分支都要安放炮台。最后问怎么打炮,才能使打掉的敌人hp最多。
解题思路:树形DP+分组背包.要守住我方基地,只要从敌方基地开始打怪,让怪死在来我方基地的路上,这样就可以从根1开始进行状态转移。由于要保证我方每个基地都收住,所以每个结点都要先找出容量为j时儿子结点打掉的最小hp,这时可通过把儿子结点dp[v][j](dp[i][j]表示i结点用j费用打掉的最大hp)当作一个物品,每个v对应一组背包,然后计算max(t,min(dp[son][j-k],dp[v][k]))获得一个组合,容量为j,里面的最小值最大,赋值给dp[i][j]。
其中有个问题就是存在代价为0的物品。所以简单的倒序的DP无法保证只选到一个物品。需要开个数组。
/* HDU 4044 树形DP+分组背包 */ #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; const int MAXN=1010; const int INF=0x3fffffff; struct Node { int to; int next; }edge[MAXN*2]; int tol; int head[MAXN]; int dp[MAXN][220]; int price[MAXN][60]; int power[MAXN][60]; void init() { memset(head,-1,sizeof(head)); tol=0; } void add(int a,int b) { edge[tol].to=b; edge[tol].next=head[a]; head[a]=tol++; edge[tol].to=a; edge[tol].next=head[b]; head[b]=tol++; } int n,m; int tmp[MAXN]; void dfs(int u,int pre) { if(head[u]==-1||(edge[head[u]].to==pre&&edge[head[u]].next==-1))//叶子结点 {//叶子结点的条件不要错了!!!! for(int i=0;i<=m;i++)dp[u][i]=0; for(int i=0;i<=m;i++)tmp[i]=dp[u][i]; //因为存在价格为0的点。所以倒序的DP并不能保证只取一件物品 for(int i=m;i>=0;i--) { for(int j=1;j<=price[u][0];j++) if(price[u][j]<=i) dp[u][i]=max(dp[u][i],tmp[i-price[u][j]]+power[u][j]); tmp[i]=dp[u][i];//tmp数组是记录的dp的上一个状态 } return; } for(int i=0;i<=m;i++) dp[u][i]=INF; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(v==pre)continue; dfs(v,u); for(int j=m;j>=0;j--) { int t=0; for(int k=0;k<=j;k++)//这里k一定要从0开始。 t=max(t,min(dp[u][j-k],dp[v][k])); dp[u][j]=t; } } for(int i=0;i<=m;i++)tmp[i]=dp[u][i]; for(int i=m;i>=0;i--) { for(int j=1;j<=price[u][0];j++) if(price[u][j]<=i) dp[u][i]=max(dp[u][i],tmp[i-price[u][j]]+power[u][j]); //和上面一样分组背包加了个tmp数组 tmp[i]=dp[u][i]; } } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); int u,v; int T; scanf("%d",&T); while(T--) { init(); scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); add(u,v); } scanf("%d",&m); for(int i=1;i<=n;i++) { scanf("%d",&price[i][0]); power[i][0]=price[i][0]; for(int j=1;j<=price[i][0];j++) { scanf("%d%d",&price[i][j],&power[i][j]); } } dfs(1,0); printf("%d\n",dp[1][m]); } return 0; }