5906. 【NOIP2018模拟10.15】传送门(树形dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq872425710/article/details/83065857

题目大意:

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

思路:

这题是真的看不懂题意,直到看了题解…,可以证明每条边最多被走两次,所以我们用答案-只会走一次的边。我们设dp[i][0]为i结点的祖宗有没有传送门,那么他就是下面的一条链只用走一次。dp[i][1]为这个点有传送阵,儿子可以随便用,所以就等于所有子节点走到他的距离。

程序:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL N=1000005;
struct tree{LL to,next,w;}e[N*2];
LL last[N],dp[N][2];
LL n,cnt,ans;

void add(LL x,LL y,LL w){
	e[++cnt].to=y; e[cnt].next=last[x]; e[cnt].w=w; last[x]=cnt;
	e[++cnt].to=x; e[cnt].next=last[y]; e[cnt].w=w; last[y]=cnt;
}

void dfs(LL x,LL fa){
	for (LL i=last[x];i;i=e[i].next)
		if (e[i].to!=fa) dfs(e[i].to,x);
	for (LL i=last[x];i;i=e[i].next)
		if (e[i].to!=fa) {
			dp[x][1]=max(dp[x][1],dp[e[i].to][1]+e[i].w);
			dp[x][0]+=max(dp[e[i].to][1]+e[i].w,dp[e[i].to][0]);
		}
}

int main(){
	freopen("portal.in","r",stdin);
	freopen("portal.out","w",stdout);
	scanf("%lld",&n);
	for (LL i=1;i<n;i++){
		LL x,y,w;
		scanf("%lld%lld%lld",&x,&y,&w);
		add(x,y,w);
		ans=ans+w*2;
	}
	dfs(1,0);
	printf("%lld",ans-dp[1][0]);
}
阅读更多
换一批

没有更多推荐了,返回首页