【bzoj4987】Tree 树形背包dp

题目描述

从前有棵树。

找出K个点A1,A2,…,Ak。

使得∑dis(AiAi+1),(1<=i<=K-1)最小。

输入

第一行两个正整数n,k,表示数的顶点数和需要选出的点个数。

接下来n-l行每行3个非负整数x,y,z,表示从存在一条从x到y权值为z的边。

I<=k<=n。

l<x,y<=n

1<=z<=10^5

n <= 3000

输出

一行一个整数,表示最小的距离和。

样例输入

10 7
1 2 35129
2 3 42976
3 4 24497
2 5 83165
1 6 4748
5 7 38311
4 8 70052
3 9 3561
8 10 80238

样例输出

184524



题解

树形背包dp

先考虑几个显而易见的性质:

1.选出的点一定是相邻的

2.对于选出的点,如果从$a_k$再走回$a_1$,那么就相当于每条边经过了两次

由于题目没有包含$dis(a_k,a_1)$,因此就相当于选出的点中的一条链可以只经过一次,其余的需要经过两次。

那我们就可以将选点转化为选边,然后考虑树形背包:

设$f[i][j][k]$表示以$i$为根的子树中选择点$i$,共选出$j$条边,且包含的链端点数目为$k$的最小代价。

这里解释一下:当$k=0$时,相当于要从根节点遍历一遍选出的边然后再从根节点出去;$k=1$时,相当于从根节点遍历一遍,到达某链端点后不出去;$k=2$时相当于从某端点遍历到根节点,然后出去再回来到另一端点。

对于根节点与子节点之间的边,显然当$k=0$或$2$时计算两遍,否则计算一遍。

这里第二维和第三维都满足背包性质,然后就可以树形背包了。

时间复杂度$\Theta(4.5n^2)$

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 3010
using namespace std;
int head[N] , to[N << 1] , len[N << 1] , next[N << 1] , cnt , si[N] , f[N][N][3];
inline void add(int x , int y , int z)
{
	to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x , int fa)
{
	int i , j , k , l , m;
	si[x] = 1 , f[x][0][0] = f[x][0][1] = 0;
	for(i = head[x] ; i ; i = next[i])
	{
		if(to[i] != fa)
		{
			dfs(to[i] , x);
			for(j = si[x] - 1 ; ~j ; j -- )
				for(k = si[to[i]] - 1 ; ~k ; k -- )
					for(l = 2 ; ~l ; l -- )
						for(m = l ; ~m ; m -- )
							f[x][j + k + 1][l] = min(f[x][j + k + 1][l] , f[x][j][l - m] + f[to[i]][k][m] + len[i] * (2 - (m & 1)));
			si[x] += si[to[i]];
		}
	}
}
int main()
{
	int n , k , i , j , x , y , z , ans = 1 << 30;
	scanf("%d%d" , &n , &k);
	for(i = 1 ; i < n ; i ++ )
		scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z);
	memset(f , 0x3f , sizeof(f));
	dfs(1 , 0);
	for(i = 1 ; i <= n ; i ++ )
		for(j = 0 ; j <= 2 ; j ++ )
			ans = min(ans , f[i][k - 1][j]);
	printf("%d\n" , ans);
	return 0;
}
时间: 2024-12-19 16:29:45

【bzoj4987】Tree 树形背包dp的相关文章

hdu1561:树形背包dp

给定n个地点,每个地点藏有cost[i]的宝物,取得某些宝物有时需要先取其他宝物,现在让我们选m个地点问最多可以选多少宝物? 还是挺裸的树形背包dp吧,不难,关键还是中间dp的部分.可以做模板了->_-> 注意点:多组数据的话如果第一组对了然后其他都错了,那么很有可能是初始化的时候漏了.这次找可很久才知道差了e[0].clear().平时的习惯都是从1开始. --------------------------------------------------------------------

NYOJ 674 善良的国王(树形背包DP)

善良的国王 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 传说中有一个善良的国王Good,他为了不劳民伤财,每当建造一个城镇的时候都只用一条路去连接,这样就可以省很多的人力和物力,也就说如果有n个城镇,那么只需要n-1条路就可以把所有的城镇链接起来了(也就是一颗树了).但是不幸的事情发生了:有个一强大的帝国想要占领这个国家,但是由于国王Good的兵力不足,只能守护m个城镇,所以经过商量,国王Good只能从他的所有城镇中选择m个相链接的城市,并且把所有可以链接到这m

【bzoj4753】[Jsoi2016]最佳团体 分数规划+树形背包dp

题目描述 JSOI信息学代表队一共有N名候选人,这些候选人从1到N编号.方便起见,JYY的编号是0号.每个候选人都由一位编号比他小的候选人Ri推荐.如果Ri=0则说明这个候选人是JYY自己看上的.为了保证团队的和谐,JYY需要保证,如果招募了候选人i,那么候选人Ri"也一定需要在团队中.当然了,JYY自己总是在团队里的.每一个候选人都有一个战斗值Pi",也有一个招募费用Si".JYY希望招募K个候选人(JYY自己不算),组成一个性价比最高的团队.也就是,这K个被JYY选择的候

【bzoj1495】[NOI2006]网络收费 暴力+树形背包dp

题目描述 给出一个有 $2^n$ 个叶子节点的完全二叉树.每个叶子节点可以选择黑白两种颜色. 对于每个非叶子节点左子树中的叶子节点 $i$ 和右子树中的叶子节点 $j$ :如果 $i$ 和 $j$ 的颜色都为当前节点子树中颜色较多(相等视为白色)的那个,则不需要付出代价:都为较小的那个则需要付 $2f[i][j]$ 的代价:否则需要付 $f[i][j]$ . 求最小代价. 输入 输入文件中第一行有一个正整数N. 第二行有2N个整数,依次表示1号,2号,…,2N号用户注册时的付费方式,每一个数字若

P2014 选课 - 树形DP[树形背包DP]

P2014 选课 传送门 思路: 树形背包DP模型,\(f[i,j]\)表示以\(i\)为根的子树中,选了\(j\)门课的最大学分.树形DP常以子树\(i\)为阶段.树形背包DP相当于树上分组背包DP.\(f[u,j]=max\{f[u,j],f[u,j-k]+f[v,k]~|~v\in~son(u)\}\).我们枚举从u的子树v中选的课数k,将\(f[v,k]\)作为获得的价值加到\(f[u,j-k]\)得到\(f[u,j]\).注意到当前子树根节点u是必须选的,所以要从\(f[u,j-1]\

20191110luogu3698小Q的棋盘 | 树形背包dp | 贪心

luogu3698小Q的棋盘 题意: 求从树的根节点出发,走n步能经过的最多的点的数量(可以重复走点,但是重复走的步数会记录) 树形背包dp: 对于从0出发,我们可以这样走: 1.选一条岔路一直走下去 2.选一条岔路走后回到0点,再选一条岔路走下去 对应的dp转移: f[0][u][j]代表从u出发走j步不一定回到u点能到达的最大步数 f[1][u][j]代表从u出发走j步回到u点能到达的最大步数 f[0][u][j] = max(f[0][u][j],f[0][u][k] + f[1][too

poj2486Apple Tree[树形背包!!!]

Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9989   Accepted: 3324 Description Wshxzt is a lovely girl. She likes apple very much. One day HX takes her to an apple tree. There are N nodes in the tree. Each node has an amoun

BZOJ.4753.[JSOI2016]最佳团体(01分数规划 树形背包DP)

题目链接 \(Description\) 每个点有费用si与价值pi,要求选一些带根的连通块,总大小为k,使得 \(\frac{∑pi}{∑si}\) 最大 \(Solution\) 01分数规划,然后dp,设f[i][j]表示i子树选j个的最大权值和,直接暴力背包转移即可 在枚举子节点选的数量时,假设x有1.2.3.4四个子节点,复杂度为 \(1*sz[1]+sz[1]*sz[2]+(sz[1]+sz[2])*sz[3]+(sz[1]+sz[2]+sz[3])*sz[4]\) 相当于每对点在L

[CTS2019]氪金手游(容斥+树形背包DP)

降智好题.本蒟蒻VP时没想到怎么做被题面迷惑了,只会20分的“好”成绩.简直自闭了. 首先显然度为0的点是白给的,根据等比数列求和公式即可求得.然后考虑这个树如果是一颗外向树,就是每个点先父亲再自己.然后直接DP,令f[i][j]表示子树i内Σw=j的概率,转移时直接用背包转移一发即可.边是正向的直接转移,反向的加上去掉该限制的答案,并减去反向的答案.复杂度显然是O(n2) #include<bits/stdc++.h> using namespace std; const int N=101