jzoj5906 【NOIP2018模拟10.15】传送门 (portal)(性质DP)

版权声明:未经作者本人允许禁止转载。 https://blog.csdn.net/jokerwyt/article/details/83060851

Description

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

分析

样例解释是误导你的,那个解不是一般形式。

传送门就是给你一个回档机会而已。

显然不会有分叉的Y字形回档,也就是不会回到祖先再走同一条路下来。
那么设dp f [ i ] [ 0 / 1 ] f[i][0/1] 表示从i出发是否有用过传送门再走回i的最小代价,讨论一下每一颗子树是否使用传送门。
若是,则必须走回i,若否,则可以传送回i(即可以减去一条最长的枝)。f[1][1]即为答案。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;

int n;
int final[N],to[N*2],nex[N*2],w[N*2],tot;
void link(int a,int b,int v) {
	to[++tot]=b,nex[tot]=final[a],final[a]=tot;
	w[tot]=v;
}

ll f[N][2],lo[N];
void dfs(int x,int fa){
	for (int i = final[x]; i; i=nex[i]){
		int y = to[i]; if (y != fa) {
			dfs(y,x);
			lo[x]=max(lo[x],lo[y]+w[i]);
			f[x][0]+=f[y][0]+w[i]*2;
			f[x][1]+=min(f[y][0]+w[i]-lo[y],f[y][1]+w[i]*2);
		}
	}
}

int main() {
	freopen("portal.in","r",stdin);
	// freopen("portal.out","w",stdout);
	cin>>n;
	for (int i = 1; i < n; i++) {
		int u,v,w; scanf("%d %d %d",&u,&v,&w);
		link(u,v,w), link(v,u,w);
	}
	dfs(1,0);
	cout<<f[1][1]<<endl;
}

猜你喜欢

转载自blog.csdn.net/jokerwyt/article/details/83060851