[ZJOI2007]时态同步(树形DP+DFS)

2024-02-05 10:48

本文主要是介绍[ZJOI2007]时态同步(树形DP+DFS),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

P1131 [ZJOI2007]时态同步
题目描述
小Q在电子工艺实习课上学习焊接电路板。一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字1,2,3….进行标号。电路板的各个节点由若干不相交的导线相连接,且对于电路板的任何两个节点,都存在且仅存在一条通路(通路指连接两个元件的导线序列)。
在电路板上存在一个特殊的元件称为“激发器”。当激发器工作后,产生一个激励电流,通过导线传向每一个它所连接的节点。而中间节点接收到激励电流后,得到信息,并将该激励电流传向与它连接并且尚未接收到激励电流的节点。最终,激烈电流将到达一些“终止节点”――接收激励电流之后不再转发的节点。
激励电流在导线上的传播是需要花费时间的,对于每条边e,激励电流通过它需要的时间为te,而节点接收到激励电流后的转发可以认为是在瞬间完成的。现在这块电路板要求每一个“终止节点”同时得到激励电路――即保持时态同步。由于当前的构造并不符合时态同步的要求,故需要通过改变连接线的构造。目前小Q有一个道具,使用一次该道具,可以使得激励电流通过某条连接导线的时间增加一个单位。请问小Q最少使用多少次道具才可使得所有的“终止节点”时态同步?
输入输出格式
输入格式:

第一行包含一个正整数N,表示电路板中节点的个数。
第二行包含一个整数S,为该电路板的激发器的编号。
接下来N-1行,每行三个整数a , b , t。表示该条导线连接节点a与节点b,且激励电流通过这条导线需要t个单位时间。
输出格式:

仅包含一个整数V,为小Q最少使用的道具次数。
输入输出样例
输入样例#1:

3
1
1 2 1
1 3 3
输出样例#1:

2
说明
对于40%的数据,N ≤ 1000
对于100%的数据,N ≤ 500000
对于所有的数据,te ≤ 1000000
思路:
这个题正解思路是树形DP,我的思路是两遍深度优先搜索(其实也是树形DP,只是累加的方式不同,但实质上就是树形DP)。
思路是这样的,对于这一棵树,我们执行第一遍DFS的时候是要调整好树上所有节点的属性,包括深度,节点到根节点的前缀和距离(因为后面的查询边权我是利用的前缀和搞的)这些。然后第二遍DFS是核心,首先递推到叶子节点,然后对于每一个有儿子节点的节点,我们比较它们的出度路径长度并找出最大值,以及它们的路径条数,既然每一个道具都是增加一个单位,我们还要尽可能的让它少用道具,那我们对每一个节点的所有出边的操作就是分别让经过这些子节点到达叶子节点的路径长度一致。而我们只能增加长度,所以我们要求一个最大值,让这些不是最大值的边向最大值靠拢,而所需要的代价就是最大值*出边数(使用道具以后的总时间)-出边边权总值(当前的总时间),对于每一次的代价用一个ANS来记录即可。
切记long long,不然会有两个点是WA了的,改了好几次TAT。

#include<iostream> 
#include<cstdio> 
#include<cstdlib> 
using namespace std;
long long i,j,m,n,s; 
long long hd[1000001],temp; 
long long ANS; 
long long deep[1000001],dis[1000001]; 
long long dismax; 
long long sum[1000001]; 
long long ma[1000001]; 
struct data 
{ 
long long v,t,nxt; 
}a[2000001]; 
long long r() 
{ 
long long ans=0; 
char ch=getchar(); 
while(ch<'0'||ch>'9') 
{ 
ch=getchar();
} 
while(ch>='0'&&ch<='9') 
{
ans*=10; 
ans+=ch-'0'; 
ch=getchar(); 
} 
return ans; 
} 
void add(long long x,long long y,long long z) 
{ 
a[++temp].v=y;
a[temp].t=z; 
a[temp].nxt=hd[x]; 
hd[x]=temp; 
} 
void dfs(long long x) 
{ 
for(long long p=hd[x];p;p=a[p].nxt) 
{ 
if(!deep[a[p].v]) 
{ 
deep[a[p].v]=deep[x]+1; 
dis[a[p].v]=dis[x]+a[p].t;
dfs(a[p].v); 
} 
} 
} 
void dfs2(long long x) 
{ 
long long mm=0,t=0; 
for(long long p=hd[x];p;p=a[p].nxt) 
{ 
if(deep[a[p].v]>deep[x])
{ 
dfs2(a[p].v); 
if(dis[ma[a[p].v]]-dis[x]>mm) 
{ 
ma[x]=ma[a[p].v];
mm=dis[ma[a[p].v]]-dis[x]; 
} 
sum[x]+=dis[ma[a[p].v]]-dis[x];
t++; 
} 
} 
ANS+=(dis[ma[x]]-dis[x])*t-sum[x]; 
} 
int main() 
{ 
n=r(); 
s=r(); 
long long xx,yy,zz; 
for(i=1;i<n;i++) 
{ 
xx=r(),yy=r(),zz=r(); 
add(xx,yy,zz); 
add(yy,xx,zz); 
} 
temp=0; 
deep[s]=1; 
dfs(s); 
for(i=1;i<=n;i++) 
{
dismax=max(dismax,dis[i]); 
ma[i]=i;
} 
dfs2(s); 
cout<<ANS; 
return 0; 
}/* 7 1 1 2 3 1 3 1 1 4 7 3 5 5 3 6 1 6 7 2 */

这里写图片描述

这篇关于[ZJOI2007]时态同步(树形DP+DFS)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/680672

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl