[树形dp] Jzoj P5906 传送门

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

 

 

题解

  • 首先,显然不会有先传送回祖先再走同一条路下来的,这就不是最小值了;还有要经过所有点
  • 那么就可以设f[i][0/1]为走完i的子树回到i是否适用传送门的最小逃脱时间
  • 状态转移方程显然 f[i][0]+=f[son][0]+v*2 f[x][1]+=min(f[son][0]+e[i].v-d[son],f[son][1]+v*2)
  • d数组为最小层叶子节点到x的最长距离

代码

 1 #include <cstdio> 
 2 #include <iostream>
 3 using namespace std;
 4 struct edge {int to,from,v;}e[1000010*2];
 5 int n,head[1000010],cnt;
 6 long long f[1000010][2],d[1000010];
 7 bool insert(int x,int y,int z) { e[++cnt].to=y; e[cnt].from=head[x]; e[cnt].v=z; head[x]=cnt; }
 8 void dfs(int x,int fa)
 9 {
10     for (int i=head[x];i;i=e[i].from)
11         if (e[i].to!=fa)
12             dfs(e[i].to,x),d[x]=max(d[x],d[e[i].to]+e[i].v),
13             f[x][0]+=f[e[i].to][0]+e[i].v*2,f[x][1]+=min(f[e[i].to][0]+e[i].v-d[e[i].to],f[e[i].to][1]+e[i].v*2);
14 }
15 int main()
16 {
17     freopen("portal.in","r",stdin),freopen("portal.out","w",stdout);
18     scanf("%d",&n);
19     for (int i=1,x,y,z;i<=n-1;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z),insert(y,x,z);
20     dfs(1,0);
21     printf("%lld",f[1][1]);
22 }

 

posted @ 2018-10-15 20:07  BEYang_Z  阅读(211)  评论(0编辑  收藏  举报