【JZOJ A组】传送门

版权声明:转载者乖乖♂站好 https://blog.csdn.net/Eric1561759334/article/details/83067520

Description

        8102年,Normalgod在GLaDOS的帮助下,研制出了传送枪。但GLaDOS想把传送枪据为己有,于是把Normalgod扔进了一间实验室。这间实验室是一棵有n个节点的树。现在Normalgod在一号节点,出口也在一号节点,但为了打开它,必须经过每一个节点按下每个节点的开关,出口才能打开。GLaDOS为了杀死Normalgod,开始在实验室里释放毒气,因此Normalgod必须尽快逃出这间实验室。
        当然,Normalgod手中的传送枪是可以使用的。传送枪可以发射出两个颜色不同的传送门。Normalgod可以从其中一个传送到另一个。尽管传送枪可以在视野范围内的任何一个经过特殊处理的表面打开一扇传送门,但这间实验室的设计使得Normalgod只能在他所处的房间内打开一个传送门。 在已经存在了一个同颜色的传送门时,打开新的传送门会使与它同颜色的旧门消失。传送和打开传送门所需时间为0。
         显然,利用传送枪会让Normalgod更快解决谜题,可Normalgod死在了按下最后一个按钮的路上。尽管如此,GLaDOS还是很想知道到底Normalgod最快能用多久逃出去,这对她的实验室设计方法论有重要的指导作用。作为GLaDOS的算法模块,你要完成这个任务。本题时限为2000ms

Input

第一行一个整数n。之后n-1行,每行三个整数ui,vi,ai ,表示有一条从ui 连向vi ,花费时间为ai 的通道。

Output

一行一个数T,表示最小的脱逃时间。

Sample Input

5
1 2 2
2 3 3
2 4 5
1 5 1

Sample Output

13

样例说明

1–> open1–> 5–> open2–> use(1)–> 2–> 3–> open2–> use(1)–> 2–> 4–> open2–> use(1)–> exit

Data Constraint

在这里插入图片描述

思路

题意:给定n个结点的树,每条边权wi,可以进行传送门操作,求经过每个结点并最终回到根节点的最短路径长度。

  1. 易知:每条边至多经过2次。
  2. 2.那么最长距离总权值2,那么我们只需要使经过一次的边的总和更大,则长度=总权值2-选用的单边权值之和。

设dp[i][0/1]
0表示在i点及i点儿子设传送门所能得到的最大总和
1 表示不在i点及i点儿子设传送门所能得到的最大总和

首先,对于dp[i][1]的情况,一定存在i点的祖先中有传送门,这样才能使结果更优。所以对于他的每一个儿子都能跳回到他的祖先。但实际上只有使一个儿子跳回祖先时,才能保证fa->i的边经过两次。
否则转化为dp[i][0]的情况。则我们要使选的儿子最优。
dp[i][1]=max(dp[vi][1]+wi);
其次,对于dp[i][0]的情况,在每个儿子中设立传送门并不会影响到其他儿子,因为总能从儿子回到i时再在i重设传送门。所以我们就取每个儿子设与不设的最优值之和。
dp[i][0]=Σmax(dp[vi][0],dp[vi][1]+wi);

代码

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll maxn=1e6+77;
long long n,f[maxn][2],d[maxn],list[maxn],cnt;
struct E
{
	ll to,next,v;
}e[maxn*2];
void add(ll u,ll v,ll val)
{
	e[++cnt].to=v; e[cnt].next=list[u]; list[u]=cnt; e[cnt].v=val;
}
void dfs(ll u,ll fa)
{
	for(ll i=list[u]; i; i=e[i].next)
	{
		ll v=e[i].to; if(v==fa) continue;
		dfs(v,u);
		d[u]=max(d[u],d[v]+e[i].v);
		f[u][0]+=f[v][0]+e[i].v*2; f[u][1]+=min(f[v][0]+e[i].v-d[v],f[v][1]+e[i].v*2);
	}
}
int main()
{
	freopen("portal.in","r",stdin),freopen("portal.out","w",stdout);
	scanf("%lld",&n);
	for(ll i=1,x,y,z; i<=n-1; i++) scanf("%lld%lld%lld",&x,&y,&z),add(x,y,z),add(y,x,z);
	dfs(1,0);
	printf("%lld",f[1][1]);
} 

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/83067520