hdu 1011 树型DP依赖背包

题意:你作为星河站队的leader,手下有m个trooper;现在让你去攻占一个基地:有n个洞穴组成,入口是洞穴1,洞穴之间用n-1条边链接,每个洞穴里面包括x个bugs,和他们的brains,你的每个trooper可以消灭20个bugs;问你最多可以得到多少个brains。

需要注意的是:你没做过的叶子必须要留人,也就是说就算某个地方的bug是0个,你也要牌一个trooper过去。

写这个题目的时候,开始用的是以前的依赖背包的思想,而且代码也是按照依赖背包写的,写的比较长,也比较繁琐,主要思路是:

因为入口是1,所以从1开始,设P=1,P是访问到的节点编号,设dp[i]表示i是需要的trooper数量,当作价格,dp[i]是得到的brains数量,当作价值:

1、遍历P的所有孩子,如果P的孩子i还有孩子,P=i,转到1,遍历完以后,如果所有的孩子都没有子孩子,转到2,否组转到3;

2、对所有的孩子进行01背包:初始化dp都是P的价值,然后进行01背包,然后把dp[i]对应的值都后移P的价格。因为如果想到到达P的孩子,必须到达P。然后回溯到上一层1,继续遍历P;

3、由于P的有些孩子还有孩子,那么处理的时候就要按照不同的情况进行01和分组背包处理,对于没有孩子的孩子,按照01背包处理,对于有孩子的孩子,对其进行分组背包的处理,然后回溯到上一层1继续遍历P;

代码如下:

/*#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
#define N 110
int num,total_price,dp[N][N];
struct Room{
    int price,value;
}room[N];
bool visited[N];
vector <int> connected[N];
void init()
{
    int i,x,y;
    memset(dp,sizeof(dp));
    memset(visited,true,sizeof(visited));
    for(i=0;i<=num;i++) connected[i].clear();
    for(i=1;i<=num;i++)
    {
        scanf("%d%d",&room[i].price,&room[i].value);
        room[i].price=ceil(room[i].price/20.0);
        if(room[i].price>total_price)        visited[i]=false;
    }
    for(i=1;i<num;i++)
    {
        scanf("%d%d",&x,&y);
        connected[x].push_back(y);
        connected[y].push_back(x);
    }
}
void dfs(int key)
{
    visited[key]=false;
    int i,j,k;
    for(i=room[key].price;i<=total_price;i++) dp[key][i]=room[key].value;
    for(i=0;i<(int)connected[key].size();i++)
    {
        int s=connected[key][i];
        if(!visited[s]) continue;
        dfs(s);
        for(j=total_price;j>=room[key].price;j--)
        {
            for(k=1;k+j<=total_price;k++)
            {
                if(dp[s][k])
                dp[key][j+k]=max(dp[key][j+k],dp[key][j]+dp[s][k]);
            }
        }
    }
}
int main()
{
    while(cin>>num>>total_price&&((num+1)||(total_price+1)))
    {
        init();
        if(!total_price)
        {
            cout<<"0"<<endl; continue;
        }
        dfs(1);
        cout<<dp[1][total_price]<<endl;
    }
}*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <list>
using namespace std;
#define N 105
struct Room{
    int price,value;
}room[N*N];
bool map[N][N],de_room[N],de_map[N];
list <int>tree[N];
int num,ans,num_i,num_j;
void update(int key)
{
    de_room[key]=false;
    int i;
    tree[key].clear();
    for(i=1;i<=num;i++)
    {
        if(map[key][i]&&de_room[i])
        {
            tree[key].push_back(i);
            de_room[i]=false;
        }
    }
    list <int>::iterator p=tree[key].begin();
    while(p!=tree[key].end())
    {
        update(*(p++));
    }
}
void fun(int key)
{
    int dp[N],i,k;
    memset(dp,sizeof(dp));
    list <int> ::iterator p=tree[key].begin();
    while(p!=tree[key].end())
    {
        if(tree[*p].empty())
        {
            k=0;
            if(room[*p].price==0)
            k=1;
            for(i=total_price;i>=room[*p].price+k;i--)
            {
                dp[i]=max(dp[i],dp[i-room[*p].price-k]+room[*p].value);
            }
        }
        else
        {
            fun(*p);
            for(i=total_price;i>=0;i--)
            {
                list <int> ::iterator q=tree[*p].begin();
                while(q!=tree[*p].end())
                {
                    if(i>=room[*q].price)
                    dp[i]=max(dp[i],dp[i-room[*q].price]+room[*q].value);
                    q++;
                }
            }
            tree[*p].clear();
        }
        p++;
    }
    tree[key].clear();
    if(key==num_i)
    {
        if(total_price-room[num_i].price>=0)
        ans=max(ans,dp[total_price-room[num_i].price]+room[num_i].value);
        return ;
    }
    for(i=total_price;i>=0;i--)
    {
        if(dp[i]<=0)
        {
            room[++num_j].price=room[key].price;
            if(room[key].price==0)
            room[num_j].price+=1;
            room[num_j].value=room[key].value;
            tree[key].push_back(num_j);
            break;
        }
        if(i+room[key].price<=total_price)
        {
            room[++num_j].price=i+room[key].price;
            room[num_j].value=dp[i]+room[key].value;
            tree[key].push_back(num_j);
        }
    }
}

int main()
{
    while(scanf("%d%d",&num,&total_price))
    {
        ans=0;
        if(num==-1&&total_price==-1)
        return 0;
        memset(de_map,sizeof(de_map));
        memset(map,false,sizeof(map));
        int i,y;
        for(i=1;i<=num;i++)
        {
            scanf("%d%d",&room[i].value);
            room[i].price=ceil(room[i].price/20.0);
            if(room[i].price>total_price)
            de_map[i]=false;
        }
        for(i=1;i<num;i++)
        {
            scanf("%d%d",&y);
            if(de_map[x]&&de_map[y])
            map[x][y]=map[y][x]=true;
        }
        if(total_price==0)
        {
            cout<<"0"<<endl;
            continue;
        }
        memset(de_room,sizeof(de_room));
        num_i=1;num_j=num;
        update(1);
        fun(1);
        cout<<ans<<endl;
    }
}

上边的思想和代码都比较繁琐,后来在网上参考了一些代码,用的其实还是依赖背包的思想,只是方法变了。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
#define N 110
int num,&room[i].value);
        room[i].price=ceil(room[i].price/20.0);
        if(room[i].price>total_price)        visited[i]=false;//小小的优化,就是如果这个点的price比total_price还大,那么就不用访问了
    }
    for(i=1;i<num;i++)
    {
        scanf("%d%d",dp[key][j]+dp[s][k]);
            }
        }
    }
}
int main()
{
    while(cin>>num>>total_price&&((num+1)||(total_price+1)))
    {
        init();
        if(!total_price)
        {
            cout<<"0"<<endl; continue;
        }
        dfs(1);
        cout<<dp[1][total_price]<<endl;
    }
}
其实对于这个代码还有可以优化的地方,只是这样写比较简单,并且也可以过,所以就省了,如果谁有优化方法,欢迎留言交流!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结