M - GeoDefense (树形dp+分组背包)

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

题意:

给一棵树,树根一定是1,敌人在1位置,每个叶子节点是你的基地,每个节点(包括1节点和你的基地)可以建一个防御塔,每个节点有多种防御塔供你选择,告诉你每种防御塔的价钱和防御能力。你现在有m这么多钱,你可以所有节点上建塔,每个节点只能建一个或不建塔。敌人很聪明,它会去摧毁防御最弱的路线(路线上所有点的防御能力之和)的基地。问你防御最弱的路线防御能力的最大值可以是多少?

思路:

树形dp+分组背包,

根据题意,我们要使最薄弱的基地的攻击力最大化。由于每个节点最多只能放一个大炮,所以我们先求出节点i给定花费j的攻击力最大值,用p[i][j]来表示。

我们设以节点t为根节点花费j的最大攻击力d[now][j]。现在分析节点now:

1.now是叶子节点,只需考虑自身防御情况,所以d[now][j]=p[now][j]。

2.now不是叶子节点。先考虑不在节点t上放大炮,遍历子树,求出花费j子树最小值的最大组合。然后考虑分配k花费给节点t,j-k花费给子树的最大组合。

代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=1100;
#define inf 0x7ffffff

vector<int> son[maxn];
int n,m,dp[maxn][250],vis[maxn],p[maxn][250];

void dfs(int now)
{
    vis[now]=1;
    if(now!=1&&son[now].size()==1)//找为树叶
    {
        for(int j=0;j<=m;j++)
        dp[now][j]=p[now][j];
        return ;
    }
    for(int j=0;j<=m;j++)   dp[now][j]=inf;//初始化
    for(int i=0; i<son[now].size();i++)//只分配给子树时
    {
        int next=son[now][i];
        if(vis[next])    continue;
        dfs(next);
        for(int j=m;j>=0;j--)
        {
            int maxx=0;
            for(int k=0;k<=j;k++)
                maxx=max(maxx,min(dp[now][j-k],dp[next][k]));//子树最小值最大组合
            dp[now][j]=maxx;
        }
    }
    for(int j=m;j>=0;j--)
        for(int k=0;k<=j;k++)
            dp[now][j]=max(dp[now][j],dp[now][j-k]+p[now][k]);//更新,子树分配j-k花费,根节点分配k花费  
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0;i<=n;i++)
            son[i].clear();
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            son[x].push_back(y);
            son[y].push_back(x);
        }
        cin>>m;
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++)
        {
            int k,c,w;
            scanf("%d",&k);
            for(int j=0;j<k;j++)
            {
                scanf("%d%d",&c,&w);
                p[i][c]=max(p[i][c],w);
            }
            for(int j=1;j<=m;j++)
                p[i][j]=max(p[i][j],p[i][j-1]);//求出节点i处j花费的最大防御
        }
        memset(dp,0,sizeof(dp));
        memset(vis,0,sizeof(vis));
        dfs(1);
        cout<<dp[1][m]<<endl;
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值