HDU-6326 Problem H. Monster Hunter(贪心模拟)

题目:给定一棵 n 个点的树,除 1 外每个点有一只怪兽,打败它需要先消耗 ai点 HP,再恢复 bi点 HP。求从 1 号点出发按照最优策略打败所有怪兽一开始所需的最少 HP。

思路:以 1 为根将树转化成有根树,那么每只怪兽要在父亲怪兽被击败后才能被击败。假如没有父亲的限制,会产生一个最优的攻击顺序:

第一步:将怪兽分成两类:a < b 的和 a ≥ b 的,前一类打完会加血,后一类打完会扣血,显然最优策略下应该先打第一类再打第二类。对于 a < b 的怪兽,显然最优策略下应该按照 a 从小到大打。

第二步对于 a ≥ b 的怪兽,考虑两只怪兽 i,j,先打 i 再打 j 的过程中血量会减少到 HP + min(−ai,−ai+ bi− aj),因为 a ≥ b,所以这等于 HP−ai−aj+bi。同理先打 j 再打 i 的过程中血量会减少到 HP − ai− aj+ bj。可以发现按照任何顺序都只和 b 有关,最优策略下需要让血量尽可能多,因此要按照 b 从大到小打。

第三步:加上父亲的限制,根据之前的优先级将子节点与父节点合并,即打完父亲后立即打这个子节点是最优的。

具体实现起来就是用优先队列来贪心了,中间合并时用并查集。   最开始写完代码,怎么改都是很正确,然而一交就wa,就很烦,拿数据本地跑发现怎么就第一组数据正确???,后面的都是一个数!!!然后发现竟然是0号节点没有初始化(代码风格不同吧,最后我的代码用的有0这一节点,答案存在了0这个点上)。。

#include 
using namespace std;
typedef long long ll;
const int maxn=200005;
struct node{
    int id,ti;
    ll a,b;
    bool operator < (const node &o)const
    {
        int d1=o.ad2;//第一步分类
        if(d1>0) return o.ab;//第二步分类
    }
};
priority_queueq;
node a[maxn];
int n,m,t;
vectorg[maxn];
int fa[maxn],f[maxn],vis[maxn];

int init()
{
    while(!q.empty())q.pop();
    for(int i=0;i<=n;i++)
    {
        g[i].clear();
        a[i].a=a[i].b=0;
        a[i].id=a[i].ti=0;
        fa[i]=0;
        f[i]=i;
        vis[i]=0;
    }
}
void dfs(int u,int pre)
{
    fa[u]=pre;
    for(int i=0;i

 

你可能感兴趣的:(多校,贪心,模拟)