有道面试 时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte 描述
有N个村庄,村庄之间有N-1条路,每条路都有一个长度。这些村庄和路形成了一个树形结构。现在要求从某个村庄出发,通过这些路访问所有的村庄,起点村庄当做已经被访问过。现在有若干个村庄可以作为起点村庄。 问访问全部的村庄要走的路程之和最小是多少。 输入
输入的第一行为一个正整数N(1≤N≤100000)。接下来的N-1行每行三个数X,Y,Z(1<=X,Y<=N, 1<=Z<=10000)表示X号村庄和Y号村庄间有一条长度为Z的路。接下来的一行包含N个数每个数不是0就是1,若第i个数是1表示可以选择该点为起始村庄否则不可以。若无法访问全部村庄输出-1。 输出
输出一个非负整数表示访问全部的村庄所要走的最小路程之和。 样例输入 5 样例输出 12 题目来源 BNU CBG
|
题目地址: http://218.194.91.48/acmhome/problemdetail.do?&method=showdetail&id=1368
树形DP , 做过HDU 4123之后,这题似乎成了水题。。。
一样的,DFS跑两遍,寻找最长路径。
第一遍更新向下的最长路径,第二遍更新向上的最长路径,然后比较得到真正的最长路。
#include<cstdio>
struct Edge{
int gt,nx,len;
}edge[210000];
int ef[110000],tol;
bool has[110000];
void add_edge(int u,int v,int len){
edge[tol].gt=v;
edge[tol].len=len;
edge[tol].nx=ef[u];
ef[u]=tol++;
}
void exist(int a,int &num){
if(!has[a]){
has[a]=true;
num++;
}
}
__int64 dp1[110000],dp2[110000];
int dir[110000];
void dfs1(int u,int last){
int v,k;
__int64 tmp;
dp1[u]=dp2[u]=0;
for(k=ef[u];k;k=edge[k].nx){
v=edge[k].gt;
if(v==last) continue;
dfs1(v,u);
tmp=dp1[v]+edge[k].len;
if(tmp>dp1[u]){
dp2[u]=dp1[u];
dp1[u]=tmp;
dir[u]=v;
}
else if(tmp>dp2[u]){
dp2[u]=tmp;
}
}
}
void dfs2(int u,int last,int Len){
int v,k;
if(dp1[u]<Len){
dp1[u]=Len;
}
for(k=ef[u];k;k=edge[k].nx){
v=edge[k].gt;
if(v==last) continue;
if(dir[u]==v){
dfs2(v,u,(Len>dp2[u]?Len:dp2[u])+edge[k].len);
}
else{
dfs2(v,u,dp1[u]+edge[k].len);
}
}
}
int s[110000];
int main(){
int n,i,a,b,len,num;
__int64 sum,mx;
scanf("%d",&n);
tol=1;
num=0;
sum=0;
for(i=1;i<n;i++){
scanf("%d%d%d",&a,&b,&len);
add_edge(a,b,len);
add_edge(b,a,len);
exist(a,num);
exist(b,num);
sum+=len;
}
for(i=1;i<=n;i++){
scanf("%d",&s[i]);
}
if(n==1 && s[1]){
puts("0");
}
else if(num<n){
puts("-1");
}
else{
dfs1(1,0);
dfs2(1,0,0);
mx=0;
for(i=1;i<=n;i++){
if(s[i]){
if(dp1[i]>mx) mx=dp1[i];
}
}
printf("%I64d\n",sum+sum-mx);
}
return 0;
}