背包专题小结

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
//树形DP
//题意: n间房子,m个士兵;每个士兵可以在一个房间里解决20个bug,不足20个也要一个
//      士兵,这些房子是树形结构,每次到达一个房子,必须把它前面的房子里的bug解决
//      了;
//      然后给n个房间的bug数,和解决这些bug得到的利益。
//      然后给的是房间的树形结构。
//      总是从编号为1的房间作为入口。
//解题思路:
//     前向星存图,并不要存成树,存成一个图,还是双向的。
//     
struct Node
{
    int now,to;
}edge[105];
int cnt,head[105],vis[105];
void init()
{
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
}
void add(int no,int to)
{
    edge[cnt].now=no;
    edge[cnt].to=head[to];
    head[to]=cnt++;
}
int bug[105],p[105];
int n,m;
int dp[105][105];//在i点放j人能得到的最多的能量;
int dfs(int root)
{
    vis[root]=1;
    int cost = (bug[root]+19)/20;
    for(int i=cost;i<=m;i++)
        dp[root][i]=p[root];//小于cost的无法获得经验;
    for(int i=head[root]; i!=-1; i=edge[i].to)
    {
        int v=edge[i].now;
        if(!vis[v])
        {
            dfs(v);
            for(int j=m;j>=cost;j--)
                for(int k=1;j+k<=m;k++)
                    if(dp[v][k])
                        dp[root][j+k]= max(dp[root][j+k],dp[root][j]+dp[v][k]);
        }     
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==-1 && m ==-1)
            break;
        for(int i=1;i<=n;i++)
            scanf("%d%d",&bug[i],&p[i]);
        init();
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        if(!m)
        {
            printf("0\n");
            continue;
        }
        memset(dp,0,sizeof(dp));
        dfs(1);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}

 

posted on 2016-05-01 21:15  bai_yan  阅读(140)  评论(0编辑  收藏  举报

导航