HDU5242.Game——贪心

http://acm.hdu.edu.cn/showproblem.php?pid=5242

一棵树有n个结点,n-1条边,每个结点有个权值。每次可以获得从根节点走到叶子结点所有结点的权值和,但是每个结点的权值只能使用一次。求走k次所能获得的最大权值和

dfs1求出所有结点到根节点的权值和,然后按从大到小排序,根据这个顺序,dfs2求出每个结点到根节点的权值和,遍历过的结点的权值不能用。

然后再从大到小排个序,取前面的k个

每次选择一个叶子结点走到根节点,相当于每次取一条单链,对于有交叉的两条链,先选权值大的肯定是最优的,因为对于某条跟它们没有交叉的链来说,这样子的操作并不会影响到它

#include <bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
const int maxn = 100010;
using namespace std;
typedef long long LL;
int n,m;
LL a[maxn],x[maxn];
bool vis[maxn];
struct Edge{
    int to,next;
}edge[maxn<<1];int head[maxn],tot;
void init()
{
    tot=0;
    clr(head,0xff);
}
void addedge(int u,int v)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
struct Node{
    LL sum;
    int id;
    bool operator<(const Node&a)const{
        return sum>a.sum;
    }
}node[maxn];
LL dfs1(int u)
{
    if(vis[u]) return node[u].sum;
    node[u].sum=a[u];
    vis[u]=true;
    for(int i=head[u];~i;i=edge[i].next){
        int v=edge[i].to;
        node[u].sum+=dfs1(v);
    }
    return node[u].sum;
}
LL dfs2(int u)
{
    if(vis[u]) return 0;
    LL w=a[u];
    vis[u]=true;
    for(int i=head[u];~i;i=edge[i].next){
        int v=edge[i].to;
        w+=dfs2(v);
    }
    return w;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
    int T,cas=1;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        clr(node,0);
        for(int i=1;i<=n;++i){
            scanf("%I64d",&a[i]);
            node[i].id=i;
        }
        clr(vis,false);
        init();
        int u,v;
        for(int i=1;i<n;++i){
            scanf("%d%d",&u,&v);
            addedge(v,u);
        }
        for(int i=1;i<=n;++i){
            if(!vis[i]){
                dfs1(i);
            }
        }
//        cout<<"-----"<<endl;
        sort(node+1,node+n+1);
        clr(vis,false);
        for(int i=1;i<=n;++i){
            x[i]=dfs2(node[i].id);
        }

        LL ans=0;
        sort(x+1,x+n+1,greater<LL>());
//        for(int i=1;i<=n;++i) cout<<x[i]<<" ";cout<<endl;
        for(int i=1,cnt=0;i<=n,cnt<m;++i)
            ans+=x[i],cnt++;
        printf("Case #%d: %I64d\n",cas++,ans);
    }
    return 0;
}
时间: 2024-07-30 19:18:56

HDU5242.Game——贪心的相关文章

hdu5242 上海邀请赛 优先队列+贪心

题意是给你一棵树    n个点 n-1条边   起点是1   每个点都有权值 每次能从根节点走到叶子节点   经行k次游戏 每次都是从1开始    拿过的点的权值不能拿第二次   问最大权值和: 开始看到题时也没想到什么方法  就按照常规的来  结果超时了   试着优化了好多次  最后过了   百度题解说是树链剖分    醉了    还没学!!! 说说我的做法吧    map[i]=a表示i节点的跟节点为a节点   从所有叶子节点开始入队(有点队列里有三个变量  分别是节点编号  权值  深度

HDU5242 Game(树上贪心)

题目链接 Game 题目的意思很简单, 就是要找一棵树权值最大等等前K条链. 在本题中,走的次数等于min(叶子结点个数,k) tree[i].sum意为从i号结点出发走到某个叶子结点能得到的最大总价值. pson[i]表示i号结点若要获得最大价值那么下一步该怎么走. 显然tree[i].sum和pson[i]是从i的各个儿子转移得到的. 那么先做一遍DFS计算出tree[i].sum, 再排序. 然后贪心,从价值最大的那个结点开始选,从大到小. 选的时候,要把他中途经过的结点全部屏蔽(就是说被

【uva 1615】Highway(算法效率--贪心 区间选点问题)

题意:给定平面上N个点和一个值D,要求在x轴上选出尽量少的点,使得对于给定的每个店,都有一个选出的点离它的欧几里德距离不超过D. 解法:先把问题转换成模型,把对平面的点满足条件的点在x轴的直线上可得到一个个区间,这样就是选最小的点覆盖所有的区间的问题了.我之前的一篇博文有较详细的解释:关于贪心算法的经典问题(算法效率 or 动态规划).代码实现我先空着.挖坑~

【贪心+Treap】BZOJ1691-[Usaco2007 Dec]挑剔的美食家

[题目大意] 有n头奶牛m种牧草,每种牧草有它的价格和鲜嫩度.每头奶牛要求它的牧草的鲜嫩度要不低于一个值,价格也不低于一个值.每种牧草只会被一头牛选择.问最少要多少钱? [思路] 显然的贪心,把奶牛和牧草都按照鲜嫩度由大到小排序,对于每奶牛把鲜嫩度大于它的都扔进treap,然后找出后继. 不过注意后继的概念是大于它且最小的,然而我们这里是可以等于的,所以应该是找cow[i].fresh-1的后继,注意一下…… 1 #include<iostream> 2 #include<cstdio&

POJ1017 Packets(贪心算法训练)

Time Limit: 1000MS          Memory Limit: 10000K          Total Submissions: 51306          Accepted: 17391 Description A factory produces products packed in square packets of the same height h and of the sizes 1*1, 2*2, 3*3, 4*4, 5*5, 6*6. These pro

ZOJ 3946 Highway Project 贪心+最短路

题目链接: http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3946 题解: 用dijkstra跑单元最短路径,如果对于顶点v,存在一系列边(ui,v)使得dis[v]最小(dis[v]表示0到v的距离).这些边能且只能选一条,那么我们自然应该选cost最小的那个边了. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #inc

CoderForce 140C-New Year Snowmen(贪心)

题目大意:有n个已知半径的雪球.堆一个雪人需要三个尺寸不同的雪球,问用这些雪球最多能堆多少个雪人? 题目分析:先统计一下每种尺寸的球的个数,从三种最多的种类中各取出一个堆成雪人,这样贪心能保证的到的数目最多. 代码如下: # include<iostream> # include<map> # include<vector> # include<cstdio> # include<queue> # include<algorithm>

计蒜客 跳跃游戏(贪心)

给定一个非负整数数组,假定你的初始位置为数组第一个下标.数组中的每个元素代表你在那个位置能够跳跃的最大长度. 请确认你是否能够跳跃到数组的最后一个下标. 例如: A = [2,3,1,1,4], return ture A = [3,2,1,0,4], return false. 格式: 第一行输入一个正整数n,接下来的一行,输入数组A[n].如果能跳到最后一个下标,输出"true",否则输出"false" 样例1 ????输入:???? ????????5 ???

BZOJ 2525 [Poi2011]Dynamite 二分+树形贪心

题意: n个点,一棵树,有些点是关键点,可以将m个点染色. 求所有关键点到最近的被染色点的距离的最大值最小. 解析: 反正从这道题我是学了一种做题思路? 大爷讲课的时候说的:一般选择某些点的代价相同的话都是贪心,代价不同的话一般都是DP. 想想也挺对的,不过就是没有感悟到过? 反正这题考试的时候我是直接D了贪心的- -! 忘了为啥D了. 显然最大值最小我们需要二分一下这个值. 然后接下来我们从下往上扫整棵树. 节点的状态有几个? 第一种是 子树内没有不被覆盖的关键点,并且子树中有一个节点的贡献可