这个题比赛的时候没做出来,看到题解的时候说是什么数链抛分,本菜鸟真的没看懂啊,看了看榜首就用一个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;
}