G-取快递 SDU2020个人排位赛#3

该篇博客探讨了如何在具有树形结构的学校环境中,寻找最接近多个宿舍楼的快递代收点。问题涉及图论和最短路径算法,通过DFS遍历找到每个节点相对于宿舍楼的最短距离,以确定最佳候选位置。给出的C++代码实现了这一算法,输出符合条件的好点数量。
摘要由CSDN通过智能技术生成

G-取快递 SDU2020个人排位赛#3

https://codeforces.com/gym/323026/problem/G

学校的快递代收处可能并不是方便,shy打算找一找有哪些地点适合作为快递代收处
学校可以看成一个无向、有边权的树,下图是一个例子。有的节点有宿舍楼,有的节点没有。快递代收处可以被安排在任何节点上,也就是说,任何节点都是一个候选位置
学校里有k个宿舍楼,而快递代收处应该尽可能离它们更近。在上图中,有三个宿舍楼,被标注为A,B,C。shy认为一个好的候选的位置应该满足以下条件:
令 d(x,y) 表示 x 和 y 之间的最短距离。如果p是一个好的候选位置,那么对于其他任意一个候选位置q(q≠p),都存在一个宿舍楼z,满足d(p,z)<d(q,z)
在上图中,候选点 2, 4, 5, 6, 8, 和 9 是好的候选点。说得更详细些,比如 6 号点距离 B 比除了 5 外其他候选点都近,并且它和 A 的距离比 5 和 A 更近。7 不是一个好的候选点,因为对于点 6 ,没有一个宿舍楼相对离 7 更近
给出学校里宿舍楼的位置,各个路的长度,以及候选的快递代收点位置,求好的候选点数量

Input
第一行两个整数n,k,3≤n≤100,000,1≤k≤n,代表节点数量和宿舍数量
接下来的n−1行,每行三个整数i,j,d,1≤i,j≤n,1≤d≤1,000,代表点i和点j之间有条长度为d的边
最后一行有k个数,代表宿舍楼所在的节点编号
Output
输出一个整数,好的候选位置数量

Examples
inputCopy
9 3
1 2 8
2 4 7
4 3 6
4 6 4
5 6 3
6 7 2
6 9 5
9 8 6
2 5 8
outputCopy
6
inputCopy
4 4
1 2 1
1 3 1
1 4 1
2 4 1 3
outputCopy
4

两个宿舍楼的路径中,点全部都是好的候选位置
可以选一个宿舍楼作为根,在树上dfs。
只要有子节点是宿舍点,则该子节点到根节点的路径全是好的点。
注意dfs时一定要用vis数组标记该点是否扫过,因为前面链式前向星建立的是双向边,直接dfs会无限循环

#include<bits/stdc++.h>
using namespace std;
int node[100100];
int head[100100];
struct edge{
    int u,v,w,nxt;
}e[200200];
int tot=0;
void addedge(int u,int v,int w){
    e[tot].u=u;
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot;
    tot++;
}
bool vis[100100];//这里注意一定要用vis数组,因为前面链式前向星建立的是双向边,直接dfs会无限循环
bool dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];i!=-1;i=e[i].nxt){
        int v=e[i].v;
        if(vis[v])continue;
        if(dfs(v)) node[u]=1;
    }
    if(node[u])return true;
    return false;
}
int main()
{
    ios::sync_with_stdio(0);
    int n,k,u,v,w,t;
    int ans=0;
    cin>>n>>k;
    memset(head,-1,sizeof head);
    for(int i=1;i<n;i++){
        cin>>u>>v>>w;
        addedge(u,v,w);
        addedge(v,u,w);
    }
    for(int i=1;i<=k;i++){
        cin>>t;
        node[t]=1;
    }
    dfs(t);
    for(int i=1;i<=n;i++){
        ans+=node[i];
    }
    cout<<ans;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值