GeoDefense
Time Limit: 12000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1802 Accepted Submission(s): 780
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
这道题是被我队友坑过来做的,当时什么都是懵逼的,推状态转移方程的时候一直不知道怎么推,好不容易过了样例又错了(本地过了就是过了)去discuss找其他的样例,总是有两组数据过不了。。。
题意:一开始有n个点,n-1条边,敌方基地是1,我方基地是所有的点,敌方只是从1点出现。现在有m钱,每个点有k种塔,每种塔有价格和造成的伤害。问敌方从1点到所有叶子节点能受到的伤害的最小值的最大是多大。。。
思路:一开始无脑dp直接wa,后来去看了大佬博客才知道要先用树状dp处理一下再用01背包更新。
大概是这样:dp[n][m]表示在n点花费m钱所造成的最大的伤害,每个点可以选择建塔或者不建,不建塔的话我们又要再加一维进行维护。。。略显麻烦,所以我们可以再来一个数组 temp[j] 来表示不建塔的情况子节点花费 j 钱最小的伤害。然后temp数组的状态转移方程是
for(k=j;k>=0;k--)
temp[j]=max(temp[j],min(temp[k],dp[son][j-k]))
我们用上一个子节点的temp来更新他的父节点的temp,然后我们再和建塔的情况min一下找最小最后找最大。这里是 temp[k],dp[son][j-k] ,因为要找最小值就要全部遍历一下。我们每遍历完一个子节点之后temp就会更新,然后下一个子节点继续更新,这就是为什么 j-k 的原因了
更新完后就更新一下建塔的dp了
AC代码:
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int maxn=1020;
const int maxm=220; // 1000000
const int INF=0x7f7f7f7f;
int dp[maxn][maxm],temp[maxn];
struct Node
{
int price,value;
}node;
vector<Node> num[maxn];
vector<int> pre[maxn];
int n,m;
void Init()
{
for (int i=1;i<=n;i++)
num[i].clear();
for (int i=1;i<=n;i++)
pre[i].clear();
return ;
}
void dfs(int now,int fa)
{
int last;
int len=pre[now].size();
for (int i=0;i<len;i++)
if (pre[now][i]==fa) continue;
else dfs(pre[now][i],now); //搜根节点
memset(temp,INF,sizeof(temp));
// cout<<now<<"--------------------"<<endl;
for (int i=0;i<len;i++)
{
last=pre[now][i];
// cout<<last<<"-----"<<endl;
if (last==fa) continue;
for (int j=m;j>=0;j--)
{
temp[j]=min(temp[j],dp[last][0]); //temp表示本点不建塔,初始化的意思是 找出最小的伤害
for (int k=j;k>=0;k--)
temp[j]=max(temp[j],min(dp[last][j-k],temp[k])); //全部循环遍历 ,找出j钱的最小伤害
}
}
for (int i=0;i<=m;i++)
{
if (temp[i]==INF) temp[i]=0;
dp[now][i]=temp[i];
}
for (int i=0;i<num[now].size();i++)
for (int j=m;j>=num[now][i].price;j--)
dp[now][j]=max(dp[now][j],temp[j-num[now][i].price]+num[now][i].value); //temp是没有建塔的
return ;
}
int main()
{
int t,start,end,k;
int price,value;
scanf("%d",&t);
while (t--)
{
Init();
scanf("%d",&n);
for (int i=1;i<n;i++) //点的关系
{
scanf("%d%d",&start,&end);
pre[start].push_back(end);
pre[end].push_back(start);
}
scanf("%d",&m);
for (int i=1;i<=n;i++) //塔
{
scanf("%d",&k);
for (int j=1;j<=k;j++)
{
scanf("%d%d",&price,&value);
node.price=price;node.value=value;
num[i].push_back(node);
}
}
dfs(1,0);
/* for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (j==m) cout<<dp[i][j]<<endl;
else cout<<dp[i][j]<<" ";*/
cout<<dp[1][m]<<endl;
}
return 0;
}