HDU4044 GeoDefense 树形dp

来源:互联网 发布:加油站会计账务软件 编辑:程序博客网 时间:2024/06/05 20:01

题意

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.
题目大意
一张游戏地图,可以看作一棵n个节点的树。描述各个相互连接的节点x和y,以及某个节点可以放的p置的大炮种类个数ki和相应的花费wi与威力ci,怪物可能从任意一个叶子节点出现。询问为了保证游戏胜利(守住根节点),用m的金钱可以使怪物的最大血量limit为多少。

题解

思路
首先,由于每个节点可以放置一个大炮或不放,那么对于每个节点的选择,就是一个分组背包。其次,对于子树的状态的选择也可以看作分组背包。因此我们需要dp两次。
由于怪物可能从任意叶子节点出现,那么limit就表示每一条路径上威力和的最小值。
值得注意的是,大炮的花费是可能为0的,我们需要处理一下。
对于代码的实现部分,储存结构上我们还是选择链式前向星,另外由于状态转移比较麻烦,为了不相互影响,我们可以用中间变量t来保存一下转移后的最终结果。
代码

#include <iostream>#include <cstring>#include <cstdio>using namespace std;template <typename Tp> void read(Tp &x){    x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}const int size=1010,INF=0x3f3f3f3f;struct date{    int ptr,nxt;}edge[size<<1];int z,n,m,p,len[size],w[size][55],c[size][55];int head[size],f[size][210];int max(int x,int y){return x>y?x:y;}int min(int x,int y){return x<y?x:y;}void add(int u,int v){     edge[++p].ptr=v;     edge[p].nxt=head[u];     head[u]=p;} void input(){    int u,v;    p=0;    memset(head,0,sizeof(head));    memset(f,0,sizeof(f));    read(n);    for(int i=1;i<n;i++)    {        read(u),read(v);        add(u,v);        add(v,u);    }    read(m);    for(int i=1;i<=n;i++)    {        read(len[i]);        for(int j=1;j<=len[i];j++)          read(w[i][j]),read(c[i][j]);//weight,value    }}void dp(int x,int pre){    int t;    f[x][0]=INF;    for(int i=head[x];i;i=edge[i].nxt)    {        if(edge[i].ptr==pre)          continue;        dp(edge[i].ptr,x);        for(int j=m;j>=0;j--)        {            t=0;            for(int k=0;k<=j;k++)              t=max(t,min(f[x][j-k],f[edge[i].ptr][k]));            f[x][j]=t;        }    }    if(f[x][0]==INF)      f[x][0]=0;    for(int j=m;j>=0;j--)    {        t=f[x][j];        for(int k=1;k<=len[x];k++)          if(j>=w[x][k])            t=max(t,f[x][j-w[x][k]]+c[x][k]);        f[x][j]=t;    }}int main(){    read(z);    while(z--)    {        input();        dp(1,-1);        printf("%d\n",f[1][m]);    }    return 0;}
原创粉丝点击