小Z的糖果店【树的中心】

题目链接

西南科技大学第十三届程序设计竞赛B题


 

Description 

小ZZ太喜欢吃糖果了,以至于每天都要花钱去买糖果,于是聪明的他决定在学校开糖果店 。

学校可以看成一个nn个节点的树,每个节点代表一栋建筑,相邻的建筑之间有一条长长的道路。

小ZZ想买下kk栋建筑来开糖果店,为了方便管理,这kk栋建筑必须是同一个联通块 。

定义一栋建筑 ii 到联通块 GG 的距离为 didi,didi 等于 ii 到 GG 中的建筑的距离的最小值;换言之, di=min(dis(i,p)|p∈G)di=min(dis(i,p)|p∈G),dis(i,p)dis(i,p) 表示点 ii 到点 pp 的树上简单距离。

小ZZ十分关心客户的分布情况,他想知道DG=max(di|1≤i≤n)DG=max(di|1≤i≤n) 。当然 DGDG 越小代表他的糖果店分布更合理。小 ZZ 想知道最小的 DGDG(GG是kk 栋建筑的的一个集合)。

Input 

第一行包含一个整数 T (1≤T≤1000)T (1≤T≤1000) 代表测试组数,对于每一组测试:

第一行两个整数 nn,kk (1≤n≤105,1≤k≤n)(1≤n≤105,1≤k≤n) 。

接下来 n−1n−1 行,每一行三个整数 u,v,w (1≤u,v≤n,1≤w≤109)u,v,w (1≤u,v≤n,1≤w≤109) 表示建筑 uu 和建筑 vv 之间有一条长为 ww 的道路。

数据保证所有测试的 nn 的和不会超过 106106。

Output 

对于每组测试,输出一行,包含一个整数,表示最小的 DGDG 。

2 5 2 1 3 1 3 5 7 2 3 1 2 4 5 5 2 1 3 1 3 5 7 2 3 1 2 4 9

6 8

Hint 

第一组测试:
选择 3,53,5 此时DGDG 为 66。

第二组测试:
选择 2,42,4 此时DGDG 为 88。


题目是中文题,不再复述题意。

  有N个点的树,选取其中K个点构成的联通块,使得到达其他点的最远距离最短。

  思路:

  我们先找到树的直径,然后在树的直径上找到树的中心,最后,我们一定要取树的中心,再通过树的中心向外展开,我们不断的选取(K-1)个目前的最大距离的点,最后得到的值一定是最小的。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define esp 1e-6
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, K, head[maxN], cnt;
struct Eddge
{
    int nex, to;
    ll len, all;
    Eddge(int a=-1, int b=0, ll c=0):nex(a), to(b), len(c) {}
}edge[maxN<<1];
inline void addEddge(int u, int v, ll w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
int A, B;
ll maxx;
inline void dfs_B(int u, int fa, ll val)
{
    if(val > maxx) { maxx = val; B = u; }
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to; ll c = edge[i].len;
        if(v == fa) continue;
        dfs_B(v, u, val + c);
    }
}
int fa[maxN];
ll to_fa_dis[maxN];
inline void dfs_A(int u, int up, ll val)
{
    if(val > maxx) { maxx = val; A = u; }
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to; ll c = edge[i].len;
        if(v == up) continue;
        fa[v] = u;  to_fa_dis[v] = c;
        dfs_A(v, u, val + c);
    }
}
int mid;    ll minn;
inline void dfs_mid(int u, ll val)
{
    ll QWQ = max(val, maxx - val);
    if(QWQ < minn) { minn = QWQ; mid = u; }
    if(fa[u] == -1) return;
    dfs_mid(fa[u], val + to_fa_dis[u]);
}
ll dfs_sum_edge(int u, int rt)
{
    ll ans = 0;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == rt) continue;
        ll tmp = dfs_sum_edge(v, u) + edge[i].len;
        ans = max(ans, tmp);
        edge[i].all = tmp;
    }
    return ans;
}
struct node
{
    int u;
    ll len;
    node(int a=0, ll b=0, ll c=0):u(a),len(b) {}
    friend bool operator < (node e1, node e2) { return e1.len < e2.len; }
};
priority_queue<node> Q;
bool inque[maxN];
inline void init()
{
    cnt = maxx = 0;
    for(int i=1; i<=N; i++) head[i] = fa[i] = -1;
    while(!Q.empty()) Q.pop();
    for(int i=1; i<=N; i++) inque[i] = false;
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &K);
        if(N == 1) { printf("0\n"); continue; }
        init();
        for(int i=1, u ,v, w; i<N; i++)
        {
            scanf("%d%d%d", &u, &v, &w);
            addEddge(u, v, w);
            addEddge(v, u, w);
        }
        dfs_B(1, 0, 0); //此时已经知道了一端点B了,我们再去把A求出来
        maxx = 0;
        dfs_A(B, 0, 0);    //这时候把A点也找到了,树的长度为maxx了
        minn = INF;
        dfs_mid(A, 0);  //现在已经知道了中心了,只需要从中心出发去跑一遍它的直接方向上的边即可、不断拓展,存进优先队列
        dfs_sum_edge(mid, 0);   inque[mid] = true;  //必选的中心点。
        for(int i=head[mid], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            inque[v] = true;
            ll all = edge[i].all;
            Q.push(node(v, all));
        }
        for(int j=1; j<K; j++)
        {
            node temp = Q.top();    Q.pop();
            int u = temp.u;
            for(int i=head[u], v; ~i; i=edge[i].nex)
            {
                v = edge[i].to;
                if(inque[v]) continue;
                ll all = edge[i].all;
                Q.push(node(v, all));
                inque[v] = true;
            }
        }
        if(Q.empty()) printf("0\n");
        else
        {
            node temp = Q.top();
            printf("%lld\n", temp.len);
        }
    }
    return 0;
}

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
苦糖果MES系统小程序是一款专为糖果生产企业所设计开发的生产管理系统小程序。它通过与企业现有的MES系统进行数据对接,帮助企业实现更高效的糖果生产管理和生产过程监控。 首先,苦糖果MES系统小程序提供了设备监控功能。通过与企业现有的设备连接,实时监测设备的运行状态和生产数据,包括设备的开机时间、停机时间、生产数量等等。这样,企业可以随时查看设备运行状态,及时发现异常情况并进行处理,提高设备的利用率和生产效率。 其次,苦糖果MES系统小程序还提供了生产计划管理功能。企业可以在系统中创建生产计划并安排生产任务,系统会根据设备的状态和产能自动进行任务分配。同时,系统还能按照生产计划的优先级进行任务排序,确保重要订单的优先生产。这样,企业可以更加科学和有序地安排生产计划,提高生产效率。 此外,苦糖果MES系统小程序还提供了生产数据分析功能。系统会自动收集设备和生产过程中的各种数据,并生成相应的报表。企业可以通过这些报表,全面了解生产过程中的各项指标,如生产速度、故障率、产量等等。这样,企业可以及时发现生产中存在的问题,并采取相应的措施进行优化和改进。 总之,苦糖果MES系统小程序通过设备监控、生产计划管理和数据分析等功能,帮助糖果生产企业实现生产过程的精细化管理和优化,提高生产效率和质量,进一步提升企业竞争力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值