一、算法分析
刚看到题的时候没什么头绪,然后先模拟了一下题上的例子,感觉本题基本框架还是最小生成树,但是需要预处理一下,刚开始的想法是把点权加到边权上面,好能求最小生成树。然后开始的实现方式就是把每个边的边权加上这个边的起点的点权,样例也能过。但是交上去之后只能过第一个点。说明这样的方法不对,那么就需要建模求解正确方法,建模时将点分为三类,起点(根)、叶子、中间点。可以证明在一个生成树中,根据题目中的走法,叶子的度数为1,且经过一次,中间点的度数等于其经过次数,叶子和中间点这两类点可以合并,但是起点会多经过(谈话)一次,然后每条边会经过两次。如果先不算起点多的那次的话,新的边权就可以设置成原来边权乘2再加上边的起点和终点权值,然后跑一遍最小生成树,把最小生成树上所有边权加起来即可。然后再算多起点多出来的那一次,因为起点是可以自定的,所以要想谈话时间最小,那就可以把点权最小的点作为起点。所以最终答案就是最小生成树中,预处理后的新边权和再加上最小点权。
二、代码及注释
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=10050;
int pa[maxn];
int r[maxn];
int n,m;
int findy(int x){
//并查集板子
if(x==pa[x]) return x;
int root=findy(pa[x]);
return pa[x]=root;
}
bool pd(int x,int y){
int xx=findy(x