【hiho1035】自驾旅行III
题目大意:给定一棵 N 个节点的有根树,1 号节点为根节点,树边有两个权值,分别为走路的代价和开车的代价。有一个旅行者开车要从根节点出发,必须遍历给定点集,可以在任何位置停止旅行,有车时可以选择开车或步行,没车只能跑路,求最小代价。
题解:这是我做过最恶心的树形dp QAQ
和 apple tree 这道题很相似,只不过这次是多了车这个东西。因此,在设计状态的时候要考虑到人和车的关系,dp[u][0] 表示人走到以 u 为根的子树中必须返回的最小权值,dp[u][1] 表示人下去但是不一定上来的最小代价,dp[u][2] 表示人和车都可以下去,人和车都必须上来的最小代价,dp[u][3] 表示人和车可以下去,人上来车不一定上来的最小代价,dp[u][4] 表示人和车可以下去,但是人和车都不一定上来的最小代价。
dp[u][0-3] 的转移方程比较好想,对于最后一种情况来说,分为走最后一棵子树的时候有没有车,如果没有车就意味着在之前遍历的某棵子树中只有人回来了,因此需要考虑两棵子树对答案的贡献。可是发现,两棵子树显然不能是同一棵,因此需要记录下最优解和次优解,以及取得最优解的是哪颗子树,这样才能合并两棵子树的贡献。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
typedef long long LL;
int n,m,key[maxn];
LL dp[maxn][5];
struct node{int nxt,to;LL w0,w1;}e[maxn<<1]; // w0 -> walk w1 -> car
int tot=1,head[maxn];
inline void add_edge(int from,int to,LL w0,LL w1){
e[++tot]=node{head[from],to,w0,w1},head[from]=tot;
}
void dfs(int u,int fa){
LL d1=0,d3=0,d4=0;
LL fi1=1e18,se1=1e18,fi2=1e18,se2=1e18; // fi1 -> dp[v][3]+w0+w1 fi2 -> dp[v][1]+w0
int x=0,y=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to; LL w0=e[i].w0,w1=e[i].w1;
if(v==fa)continue;
dfs(v,u);
key[u]+=key[v];
if(key[v]){
LL t=min(dp[v][0]+2*w0,dp[v][2]+2*w1);
dp[u][0]+=dp[v][0]+2*w0;
dp[u][2]+=t;
d1=min(d1,dp[v][1]-dp[v][0]-w0);
d3=min(d3,dp[v][3]+w0+w1-t);
d4=min(d4,min(dp[v][4]+w1,dp[v][1]+w0)-t);
LL ret1=dp[v][3]+w0+w1-t;
if(ret1<fi1)se1=fi1,fi1=ret1,x=v;
else se1=min(se1,ret1);
LL ret2=dp[v][1]+w0-t;
if(ret2<fi2)se2=fi2,fi2=ret2,y=v;
else se2=min(se2,ret2);
}
}
if(x&&y){
if(x!=y)d4=min(d4,fi1+fi2);
else d4=min(d4,min(fi1+se2,fi2+se1));
}
dp[u][1]=dp[u][0]+d1;
dp[u][3]=dp[u][2]+d3;
dp[u][4]=dp[u][2]+d4;
}
void read_and_parse(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y,w0,w1;
scanf("%d%d%d%d",&x,&y,&w0,&w1);
add_edge(x,y,w0,w1),add_edge(y,x,w0,w1);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
int x;scanf("%d",&x);
key[x]++;
}
}
void solve(){
dfs(1,0);
printf("%lld\n",dp[1][4]);
}
int main(){
read_and_parse();
solve();
return 0;
}
【hiho1035】自驾旅行III的更多相关文章
- hihocoder 1035 : 自驾旅行 III
描述 给定一棵含有 n 个结点的树,结点从 1 标号.你从 1 号结点驾车出发,希望遍历一些关键结点(访问到就好,不需要按照这些关键结点的输入顺序).每条边有两个权值,c0, c1 分别表示步行和驾车 ...
- 用Kotlin开发Android应用(III):扩展函数和默认值
这是关于Kotlin的第三篇. 原文标题:Kotlin for Android (III): Extension functions and default values 原文链接:http://an ...
- LeetCode Single Number I / II / III
[1]LeetCode 136 Single Number 题意:奇数个数,其中除了一个数只出现一次外,其他数都是成对出现,比如1,2,2,3,3...,求出该单个数. 解法:容易想到异或的性质,两个 ...
- BZOJ 3531: [Sdoi2014]旅行 [树链剖分]
3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1685 Solved: 751[Submit][Status] ...
- SPOJ GSS3 Can you answer these queries III[线段树]
SPOJ - GSS3 Can you answer these queries III Description You are given a sequence A of N (N <= 50 ...
- vijos P1780 【NOIP2012】 开车旅行
描述 小\(A\)和小\(B\)决定利用假期外出旅行,他们将想去的城市从\(1\)到\(N\)编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市\(i\)的海拔高度为 ...
- 【BZOJ-1570】BlueMary的旅行 分层建图 + 最大流
1570: [JSOI2008]Blue Mary的旅行 Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 388 Solved: 212[Submit ...
- 【Codeforces717F】Heroes of Making Magic III 线段树 + 找规律
F. Heroes of Making Magic III time limit per test:3 seconds memory limit per test:256 megabytes inpu ...
- codevs 1036 商务旅行(Targin求LCA)
传送门 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意 ...
随机推荐
- sshpass密码
使用sshpass sshpass -p "password" scp -r user@example.com:/some/remote/path /some/local/path ...
- 小程序onLaunch事件的坑
记一个小程序踩过的坑 小程序项目中app.js里面定义了globalData,即全局变量,里面定义了一个token字段 需求是这样的,每次进入小程序的时候需要检验该token有没有,没有就请求后台获取 ...
- 【机器学习实践】Jupyter Notebook安装 侧边导航栏功能 操作及其他常用扩展功能介绍
安装过程: 1. 首先我们引入jupyter_contrib_nbextension这个第三方库. 2. 在Anaconda Promot中输入命令: pip install jupyter_con ...
- 华为HCNA乱学Round 5:华为交换机基础
- BUUOJ reverse SimpleRev (爆破)
SimpleRev SimpleRev(flag需加上flag{}再提交) 注意:得到的 flag 请包上 flag{} 提交 拖到ida 找到关键函数: unsigned __int64 Decry ...
- skiplist(跳表)的原理及JAVA实现
前记 最近在看Redis,之间就尝试用sortedSet用在实现排行榜的项目,那么sortedSet底层是什么结构呢? "Redis sorted set的内部使用HashMap和跳跃表(S ...
- Linux就该这么学——安装配置VM虚拟机
Vm虚拟机下载地址 : https://cloud.189.cn/t/zAfaQvJZRziu (访问码:6717) rehl镜像下载地址 : https://cloud.189.cn/t/67BJ ...
- React 中的函数式思想
函数式编程简要概念 函数式编程中一个核心概念之一就是纯函数,如果一个函数满足一下几个条件,就可以认为这个函数是纯函数了: 它是一个函数(废话): 当给定相同的输入(函数的参数)的时候,总是有相同的输出 ...
- ps -ef
status, msg = commands.getstatusoutput("ps -ef | grep start.sh | grep -Fv grep | awk '{print $1 ...
- Wizard's Tour CodeForces - 860D (图,构造)
大意: 给定$n$节点$m$条边无向图, 不保证连通, 求选出最多邻接边, 每条边最多选一次. 上界为$\lfloor\frac{m}{2}\rfloor$, $dfs$贪心划分显然可以达到上界. # ...