您的位置:首页 > Web前端 > JavaScript

【jzoj3861】【JSOI2014】【支线剧情2 】【树形动态规划】

2017-01-17 14:57 351 查看

题目大意

给出一棵有根树,走过每一条边有一定的费用,只能从根方向往叶子方向走。你只有一个存档位,你可以选择途中的一个地方存档,任何时候你可以读档,回到存档位,也可以回到根。求最少的费用走过所有点。

解题思路

设f[i]表示i及其子树无存档从i走完子树的花费。g[i]表示i有存档走完子树的花费。f可以很暴力地求,所有都从根开始走。g我们先找一个子节点走f比走g最劣,先将它走g。在扫其他节点走f和g那个优就走那个,注意这时g要加上从根走到子节点的花费。

code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define fo(i,j,k) for(LL i=j;i<=k;i++)
#define fd(i,j,k) for(LL i=j;i>=k;i--)
using namespace std;
LL const maxn=1e6,mo=12580;
LL n,gra,begin[maxn+10],to[maxn+10],len[maxn+10],next[maxn+10],
dep[maxn+10],f[maxn+10],g[maxn+10],son[maxn+10];
void insert(LL u,LL v,LL w){
to[++gra]=v;
len[gra]=w;
next[gra]=begin[u];
begin[u]=gra;
}
void dfs(LL now){
if(!begin[now]){son[now]=1;return;}
LL p=begin[now],tmp=0;
for(LL i=begin[now];i;i=next[i]){
dep[to[i]]=dep[now]+len[i];
dfs(to[i]);
son[now]+=son[to[i]];
f[now]+=f[to[i]]+len[i]*son[to[i]];
if(f[to[i]]+len[i]*son[to[i]]-g[to[i]]-len[i]>f[to[p]]+len[p]*son[to[p]]-g[to[p]]-len[p])p=i;
}
for(LL i=begin[now];i;i=next[i])if(i!=p){
if(f[to[i]]+len[i]*son[to[i]]>=g[to[i]]+dep[to[i]])g[now]+=g[to[i]]+dep[to[i]];
else g[now]+=f[to[i]]+len[i]*son[to[i]];
}
g[now]+=g[to[p]]+len[p];
}
LL read(){
LL v=0;char ch=getchar();
for(;(ch<'0')||(ch>'9');ch=getchar());
for(;(ch>='0')&&(ch<='9');v=v*10+ch-'0',ch=getchar());
return v;
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
n=read();LL K,b,t;
fo(i,1,n){
K=read();
fo(j,1,K){
b=read();t=read();
insert(i,b,t);
}
}
dfs(1);
printf("%lld",g[1]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: