传送门:http://acm.fzu.edu.cn/problem.php?pid=2195
题型:图论
题意:中文题,不解释
分析:
试想先序遍历一棵树,必然只有根到某个叶子节点的路径不会回溯,且其他的边都会被回溯且只回溯一次,所以寻找最小的回溯权值和,只需要找到那一条权值最大的路径,然后用所有边权和减去就可以了。
最简单的办法就是单源最短路求出根到所有叶子节点的路径权值,然后选最大就可以了。
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<queue>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x3f3f3f3f;
const int M=1000010;
bool vis[M];
class Spfa { ///单源最短路o(2*ME)
typedef int typec;///边权的类型
static const int ME=1000010;///边的个数
static const int MV=1000010;///点的个数
struct E {
int v,next;
typec w;
} e[ME];
int n,le,head[MV],inque[MV];
typec dist[MV];
bool used[MV];
queue<int> q;
public:
void init(int tn) { ///传入点的个数
n=tn;
le=0;
mt(head,-1);
}
void add(int u,int v,typec w) {
e[le].v=v;
e[le].w=w;
e[le].next=head[u];
head[u]=le++;
}
bool solve(int s) { ///传入起点,下标0开始,存在负环返回false
for(int i=0; i<n; i++) {
dist[i]=inf;
used[i]=true;
inque[i]=0;
}
used[s]=false;
dist[s]=0;
inque[s]++;
while(!q.empty()) q.pop();
q.push(s);
while(!q.empty()) {
int u=q.front();
q.pop();
used[u]=true;
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
if(dist[v]>dist[u]+e[i].w) {
dist[v]=dist[u]+e[i].w;
if(used[v]) {
used[v]=false;
q.push(v);
inque[v]++;
if(inque[v]>n) return false;
}
}
}
}
return true;
}
typec getdist(int id) {
return dist[id];
}
} gx;
int main() {
int n;
while(~scanf("%d",&n)) {
int m = n-1;
int total = 0;
int u,v,w;
gx.init(n);
mt(vis,true);
vis[0] = false;
while(m--) {
scanf("%d%d%d",&u,&v,&w);
gx.add(u-1,v-1,w);
total += w;
vis[u-1] = false;
}
gx.solve(0);
int maxn = -1;
for(int i=1; i<n; i++) {
if(vis[i]) {
maxn = max(maxn,gx.getdist(i));
}
}
printf("%d\n",total-maxn);
}
return 0;
}