【BZOJ1812】riv(多叉树转二叉树,树形DP)

题意:给定一棵树,每个点有权值,每条边有边权(单向边)。你可以选取K个黑点,使得从每个点移动到距离他最近的黑点的花费(距离*点权)的总和最小。

n<=100 k<=50 w[i],a[i]<=10000

思路:见IOI2005龙凡解题报告

又是一道从父亲到儿子的树形DP

为什么要多叉转二叉?因为假设点U被选,这个被选点只会对U自己的儿子有影响,对U的兄弟并没有影响

dp[i,j,k]表示以i为根的子树,建j个节点,离i最近的被选点是k时的最小总和

\[ dp[i,j,k]=min\begin{cases} dp[l[i],t,k]+dp[r[i],j-t,k]+(dis[i]-dis[k])*a[i]\\dp[l[i],t,i]+dp[r[i],j-t-1,k] \end{cases} \]

 1 var dp:array[1..200,0..60,1..200]of longint;
 2     head,vet,next,len,l,r,tree,a,dis:array[1..1000]of longint;
 3     n,m,i,x,y,tot:longint;
 4
 5 procedure add(a,b,c:longint);
 6 begin
 7  inc(tot);
 8  next[tot]:=head[a];
 9  vet[tot]:=b;
10  len[tot]:=c;
11  head[a]:=tot;
12 end;
13
14 procedure dfs(u:longint);
15 var e,v:longint;
16 begin
17  e:=head[u];
18  while e<>0 do
19  begin
20   v:=vet[e];
21   dis[v]:=dis[u]+len[e];
22   dfs(v);
23   e:=next[e];
24  end;
25 end;
26
27 function min(x,y:longint):longint;
28 begin
29  if x<y then exit(x);
30  exit(y);
31 end;
32
33 function ask(u,i,k:longint):longint;
34 var ans,j:longint;
35 begin
36  if dp[u,i,k]<maxlongint div 3 then exit(dp[u,i,k]);
37  dp[u,i,k]:=maxlongint div 3;
38  for j:=0 to i do
39  begin
40   ans:=0;
41   if l[u]>0 then ans:=ans+ask(l[u],j,k);
42   if r[u]>0 then ans:=ans+ask(r[u],i-j,k);
43   dp[u,i,k]:=min(dp[u,i,k],ans+(dis[u]-dis[k])*a[u]);
44   if i-j-1>=0 then
45   begin
46    ans:=0;
47    if l[u]>0 then ans:=ans+ask(l[u],j,u);
48    if r[u]>0 then ans:=ans+ask(r[u],i-j-1,k);
49    dp[u,i,k]:=min(dp[u,i,k],ans);
50   end;
51  end;
52  //writeln(u-1,‘ ‘,i,‘ ‘,k-1);
53  exit(dp[u,i,k]);
54 end;
55
56 begin
57  assign(input,‘bzoj1812.in‘); reset(input);
58  assign(output,‘bzoj1812.out‘); rewrite(output);
59  readln(n,m);
60  inc(n);
61  for i:=2 to n do
62  begin
63   read(a[i],x,y);
64   inc(x);
65   if tree[x]=0 then begin l[x]:=i; tree[x]:=i; end
66    else begin r[tree[x]]:=i; tree[x]:=i; end;
67   add(x,i,y);
68  end;
69  dfs(1);
70  fillchar(dp,sizeof(dp),$7f);
71  writeln(ask(1,m,1));
72  close(input);
73  close(output);
74 end.
时间: 2024-10-12 13:25:21

【BZOJ1812】riv(多叉树转二叉树,树形DP)的相关文章

多叉树转二叉树+树形dp(codevs 1746 贪吃的九头龙 2002noi)

题目传送门 看到这个题目我们要先把问题简化了,条件中是多叉树,我们可以把它转换成二叉树,左边是儿子右边是兄弟的储存方式. 首先先判断否的部分,当总的果子小于需求,也就是N-k<M-1时输出-1. 我们再判断是的部分 如果没有大头,一定存在难受值为0的方案但是现在题目中有大头,我们就可以按按照小头的个数进行分类 1.有一个小头,我们要考虑小头和大头的难受值之和. 2.有多个小头,因为小头可以在奇偶的进行变换,所以我们只需要考虑大头的难受值. 分析到这里,我们就可以发现是树形dp我们设f[i][j]

BZOJ1864[ZJOI2006]三色二叉树[树形DP]

1864: [Zjoi2006]三色二叉树 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 773  Solved: 548[Submit][Status][Discuss] Description Input 仅有一行,不超过500000个字符,表示一个二叉树序列. Output 输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色. Sample Input 1122002010 Sample Output 5 2 HINT

[bzoj1812][IOI2006]riv_多叉树转二叉树_树形dp

riv bzoj-1812 IOI-2006 题目大意:给定一棵n个点树,要求在上面建立k个收集站.点有点权,边有边权,整棵树的代价是每个点的点权乘以它和它的最近的祖先收集站的距离积的和. 注释:$1\le n \le 100$,$1\le k \le 50$. 想法:显然,这是一道树形dp题.状态也非常容易... ...只不过,我们好像要枚举子集... 所以,我们这里有一个黑科技:多叉树转二叉树. 我们先把它转成二叉树,然后再进行转移即可. 状态:dp[i][j][k]表示以i为根的子树中选出

选课 树形DP+多叉树转二叉树+dfs求解答案

问题 A: 选课 时间限制: 1 Sec  内存限制: 128 MB提交: 6  解决: 3[提交][状态][答疑][寄存][题解] 题目描述 大 学里实行学分.每门课程都有一定的学分,学生只要选修了这门课并考核通过就能获得相应的学分.学生最后的学分是他选修的各门课的学分的总和. 每个学生都要选择规定数量的课程.其中有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如,<数据结 构>必须在选修了<高级语言程序设计>之后才能选修.我们称&l

算法进阶面试题05——树形dp解决步骤、返回最大搜索二叉子树的大小、二叉树最远两节点的距离、晚会最大活跃度、手撕缓存结构LRU

接着第四课的内容,加入部分第五课的内容,主要介绍树形dp和LRU 第一题: 给定一棵二叉树的头节点head,请返回最大搜索二叉子树的大小 二叉树的套路 统一处理逻辑:假设以每个节点为头的这棵树,他的最大搜索二叉子树是什么.答案一定在其中 第一步,列出可能性(最难部分) 1.可能来自左子树上的某课子树 2.可能来自右子树上的某课子树 3.整颗都是(左右子树都是搜索二叉树并且左子树最大小于该节点,右子树最小大于该节点) 第二步,收集信息: 1.左树最大搜索子树大小 2.右树最大搜索子树大小 3.左树

树形DP+(分组背包||二叉树,一般树,森林之间的转换)codevs 1378 选课

codevs 1378 选课 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得相应的学分. 在选修课程中,有些课程可以直接选修,有些课程需要一定的基础知识,必须在选了其它的一些课程的基础上才能选修.例如<Frontpage>必须在

树形dp入门-加分二叉树(luogu1040)

今天学习了树形dp,确实,感受到了深深的压力...一会还得去写选课那道题... 先看题目: 首先我们看到关键字:中序遍历.既然已经给出我们分数的算法,所以我们就可以通过枚举根节点来解决问题.在每一个根节点下求最优解,且记录下每一个根节点,就恰好能完成两个任务.即我们需要写两个子程序. 看代码:(请勿直接复制粘贴) #include <stdio.h> int n,point[32],f[32][32],mumber[32][32]; long long tree(int left,int ri

Vijos 1523 贪吃的九头龙 【树形DP】

贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted by JackDavid127 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,

选课(洛谷_2014)——树形dp

我是来复习一下树形dp的 这题,需要了解--左儿子右兄弟--也就是说,这是一个多叉树转二叉树的方法,儿子位置不变,兄弟的位置变成右儿子 然后就和二叉苹果树差不多了. #include<iostream> #include<cstdio> #define max(a,b) a>b?a:b using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c>'9'||c<'0'