HDU - 5242 贪心,DFS

4 篇文章 0 订阅
1 篇文章 0 订阅

这个题比赛的时候没做出来,看到题解的时候说是什么数链抛分,本菜鸟真的没看懂啊,看了看榜首就用一个dfs做的大佬,看了半天都没看懂,写得很难读,不过看了看别的博客的题解,突然就理解了。

题意:给你n个节点的值,n - 1条边,然后让找你k条路径,从树根开始(就是1),找出每条路径之和为最大值,但是如果之前走过这个节点,那么这个节点的值就变成了0,这是我第二次看到要正方两次dfs的题,第一个好像是uva上的一个也是找路径的题,记得不太清,不过我对于这些糅杂了不同知识点的题就是个白痴。

做法:先把节点用vector和数组存起来,然后用第一次dfs寻找每个路径的最后值,然后用结构体记录下来,排序,然后让权值之和最大的那条路径翻过来dfs一遍,把他经过的点全部标记一遍,然后依次dfs,新求出来的每次结果排序,找出K个最大的就行了,理解了就很简单了,加油!!!

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int fa[maxn], val[maxn], vis[maxn], total;
int n, k;
ll ans[maxn];
vector<int> son[maxn];
class node
{
public:

    int id;
    ll sum;
    bool operator < (const node & p1)
    {
        return  sum > p1.sum;
    }
}edge[maxn];
void dfs1(int now, ll vall)
{
    int son_sum = son[now].size();
    if(son_sum == 0)
        edge[total].id = now, edge[total++].sum = vall + val[now];
    for(int i = 0; i < son_sum; i++)
        dfs1(son[now][i],vall + val[now]);
}
ll dfs2(int now)
{
    if(vis[now])return 0;
    vis[now] = 1;
    return val[now] + dfs2(fa[now]);
}
void initial()
{
    memset(vis, 0, sizeof(vis));
    memset(fa, 0, sizeof(fa));
    memset(ans, 0, sizeof(ans));
    memset(edge, 0, sizeof(edge));
    for(int i = 0; i < n; i++)
        son[i].clear();
}
int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    int kase = 0;
    while(T--)
    {
        initial();
        total = 0;
        cin >> n >> k;
        for(int i = 1; i <= n; i++)
            cin >> val[i];
        for(int i = 1; i < n; i++)
        {
            int x, y;
            cin >> x >> y;
            son[x].push_back(y);
            fa[y] = x;
        }
        dfs1(1, 0);
        sort(edge, edge + total);
        for(int i = 0; i < total; i++)
            ans[i] = dfs2(edge[i].id);
        sort(ans, ans + total);
        ll ans_sum = 0;
        for(int i = total - 1; i >= 0 && k >= 1; i--, k--)
            ans_sum += ans[i];
        printf("Case #%d: %lld\n",++kase, ans_sum);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值