原题网址:https://begin.lydsy.com/JudgeOnline/contest.php?cid=1303
第一次发题解,因为本身是蒟蒻,所以怪不好意思的,请各位神犇口下留情,谢谢。
当然若有什么错误还请各位神犇纠正,本蒟蒻不胜感激。
好,步入正题。
题目描述如下:
Description
大雪履盖了整个城市,市政府要求冬季服务部门尽快将一些街道(列在一份清单中)的积雪清除掉以恢复交通,整个城市由许多交叉路口和街道构成,当然任意两个交叉路口都是直接或间接连通的,清单给出了最少的街道,使得这些街道的积雪清除后任意两个交叉路口之间有且仅有一条通路,冬季服务部门只有一辆铲雪车及一名司机,这辆铲雪车的出发点位于某个交叉路口。
无论街道上有没有积雪,铲雪车每前进一米都要消耗一升燃料,冬季服务部门要求司机在铲除清单上的所有街道的积雪的前提下,要求消耗燃料最少,积雪铲完后车可以停在任意的交叉路口。
Input
输入文件的第一行包含两个整数N和S,1≤N≤100000,1≤S≤N。N为交叉路口的总数;S为铲雪车出发的路口序号。路口的标号为1••N。
接下来的N-1行为清单上的街道,每一行包含三个用空格隔开的整数A、B、C,表示一条从交叉路口A到交叉路口B的街道,C为该街道的长度,单位为米,1≤C≤1000。
Output
输出文件仅一行包含一个整数表示清除所有积雪所需的最少的燃料数量。
Sample Input
5 1
1 2 1
2 3 1
3 5 1
3 4 1
Sample Output
5
其实刚看到这题是有点蒙,毕竟是蒟蒻,但后来看了一下,发现这不就是树嘛,所以思路就清晰了许多,再看看题面,手动推导一下,就会发现他最长的那条边是只需要走一遍的,而其他的边都是要走两边的,所以结果就很容易出来了,ans=2*所有边长度之和-最长边。
代码如下(并附带自身对代码的理解):
#include <bits/stdc++.h>
using namespace std;
int n,s,sum,tot,q;
int now[100002],son[200003],pre[200003],v[200003],d[100002];
//now当前节点,son当前节点的儿子,pre前一条到达当前节点的边,v当前权值,d当前节点到起始点的权值
bool f[100002]; //判断是否走过
void put(int a,int b,int c) //构建一棵树
{
pre[++tot]=now[a]; //tot前一条边赋值为当前描述节点a的边
now[a]=tot; //当前描述节点a的边赋值为tot
son[tot]=b; //tot的儿子赋值为b
v[tot]=c; //当前权值为c
}
void dfs(int u)
{
f[u]=1; //已走过
for(int p=now[u]; p;p=pre[p]) //从p开始一直往前面推
{
int t=son[p]; //t为p的儿子节点
if(!f[t]) //未被搜索
{
d[t]=d[u]+v[p]; //权值增加
dfs(t); //重新搜索
}
}
}
int main() {
int a,b,c;
scanf("%d%d",&n,&s);
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
sum+=c;
put(a,b,c); //建立联系(1)第一次走
put(b,a,c); //建立联系(2)返回时走的第二遍
}
dfs(s); //搜索
for(int i=1;i<=n;i++)
q=max(q,d[i]); //找出最远边
printf("%d",sum*2-q); //sum*2来回要走两遍,q最远边只会走一遍,sum*2-q总权值减去最远边回程一遍
return 0;
}
这个代码最关键的地方无疑是建立一棵树,初学者可能难以理解,奉上样例:
1
/1 |2 \3
2 3 4
1:1–2
2:1–3
3:1–4
num[1]=3
child[3]=4
pre[3]=2
child[2]=3
pre[2]=1
child[1]=2
pre[1]=0
最后,还是希望本题解对大家有所作用,同时恳请各位神犇纠正本蒟蒻的错误。
鸣谢!!!