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

善良的国王

时间限制:1000 ms  |  内存限制:65535 KB

难度:4

描述
传说中有一个善良的国王Good,他为了不劳民伤财,每当建造一个城镇的时候都只用一条路去连接,这样就可以省很多的人力和物力,也就说如果有n个城镇,那么只需要n-1条路就可以把所有的城镇链接起来了(也就是一颗树了)。但是不幸的事情发生了:有个一强大的帝国想要占领这个国家,但是由于国王Good的兵力不足,只能守护m个城镇,所以经过商量,国王Good只能从他的所有城镇中选择m个相链接的城市,并且把所有可以链接到这m个城镇的道路都毁掉以阻止强大帝国的入侵。由于毁掉道路也需要花费一定的代价,所以为了经可能的保存实力,国王Good想要毁掉最可能少的道路。现在请聪明的你帮助这位善良的国王Good吧。(m个城市可以是任意的,只要能连接在一起就可以。

输入
第一行一个t,代表有t组测试数据;

每组测试数据第一行有两个数,n,m(0<n<500,0=<m<=n)分别代表城镇总的数量和要保留的城镇数量。

接下来的n-1行,每行包括两个数字,x,y(0<x,y<=n)表示x和y连通。

输出
每组输出站一行。输出格式“case #i: ans”,i代表第i组测试数据,ans即为最少要删除的边数。
样例输入
1
10 3
1 5
1 6
1 7
7 8
7 9
7 10
6 3
6 4
3 2
样例输出
case #1: 2
树形动态规划!   同http://poj.org/problem?id=1947
AC码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
#define M 500
#define INF 9999999
vector<int> adj[M];
int f[M][M],vex[M];
int n,p,ans;
int min(int a,int b)
{
	return a>b?b:a;
}
int DP(int u)
{
	vex[u]=1;
	int i,j,k,v,len=adj[u].size();
	for(i=0;i<len;i++)
	{
		v=adj[u][i];
		vex[u]+=DP(v);
	}
	f[u][1]=len;
	for(i=0;i<len;i++)
	{
		v=adj[u][i];
		for(k=vex[u];k>=1;k--)
		{
			for(j=1;(j<k)&&(j<=vex[v]);j++)
				f[u][k]=min(f[u][k],f[u][k-j]+f[v][j]-1);
		}
	}
	if(vex[u]>=p)
		ans=min(ans,f[u][p]+(u!=1));
	return vex[u];
}
int main()
{
	int T,i,a,b,count=1;
	scanf("%d",&T);
	while(T--)
	{
		for(i=0;i<M;i++)
			adj[i].clear();
		scanf("%d%d",&n,&p);
		for(i=0;i<n-1;i++)
		{
			scanf("%d%d",&a,&b);
			adj[a].push_back(b);
		}
		ans=INF;
		memset(f,INF,sizeof(f));
		DP(1);
		printf("case #%d: %d\n",count++,ans);
	}
	return 0;
}

重建道路

时间限制: 1000MS   内存限制: 30000K
总提交: 8780   接受日期: 3954

描述

奶牛已在可怕的地震去年五月后重建农夫约翰的农场,与它的N谷仓(1 <= N <= 150,数字1 .. N)。牛没有时间来重建任何额外的道路,所以现在正是从任何给定的谷仓去任何其他谷仓的一种方式。因此,养殖场运输系统可以表示为一棵树。 农夫约翰想要知道另一地震可能造成的伤害。他想知道道路的最小数量,其破坏将隔离正好P(1 <= P <= N)从谷仓的其余部分谷仓的一个子树。

输入

*第1行:两个整数N和P *第2 .. N:N-1行,每 ??行有两个整数I和J节点i节点J的父母在道路的树。

产量

单线包含整数,表示需要对P个节点被孤立的子树被破坏道路的最小数目。

样例输入

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

样例输出

2

AC码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
#define M 500
#define INF 9999999
vector<int> adj[M];
int f[M][M],vex[M];
int n,p,ans;
int min(int a,int b)
{
	return a>b?b:a;
}
int DP(int u)
{
	vex[u]=1;
	int i,j,k,v,len=adj[u].size();
	for(i=0;i<len;i++)
	{
		v=adj[u][i];
		vex[u]+=DP(v);
	}
	f[u][1]=len;
	for(i=0;i<len;i++)
	{
		v=adj[u][i];
		for(k=vex[u];k>=1;k--)
		{
			for(j=1;(j<k)&&(j<=vex[v]);j++)
				f[u][k]=min(f[u][k],f[u][k-j]+f[v][j]-1);
		}
	}
	if(vex[u]>=p)
		ans=min(ans,f[u][p]+(u!=1));
	return vex[u];
}
int main()
{
	int i,a,b;
	scanf("%d",&T);
	for(i=0;i<M;i++)
		adj[i].clear();
	scanf("%d%d",&n,&p);
	for(i=0;i<n-1;i++)
	{
		scanf("%d%d",&a,&b);
		adj[a].push_back(b);
	}
	ans=INF;
	memset(f,INF,sizeof(f));
	DP(1);
	printf("%d\n",ans);
	return 0;
}

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

时间: 2024-10-09 05:54:38

NYOJ 674 善良的国王(树形背包DP)的相关文章

hdu1561:树形背包dp

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

【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 244

【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

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

一类有依赖的树形背包dp方法

失踪人口回归系列 这个标题是不是看起来很厉害呢233 给一道例题:有一个树,每一个节点代表一个物品,每个物品有重量和价值,每个物品必须先选父亲才能选自己.求给定重量内最大价值. 这题的思路十分的厉害.我们把树的dfs序建出来,对于dfs序上每一个点,我们考虑如果自己选那么自己子树内就可以选,否则只有在这棵子树外面才可以选. 那么我们记f[i][j]为dfs序中第i个点及以后的dfs序大小为j的联通块的最大权值,所以我们可以得出f[i][j]=max(f[i+1][j-w[i]]+v[st[i]]