F. Maximum Weight Subset(贪心or树形dp解法)
题:https://codeforces.com/contest/1249/problem/F
题意:给一颗树,边权为1,节点有点权,问取到一个点集,俩俩之间路径超过k,是点权和最大
思路:贪心地取点,先将点按照深度经行排序,每一次,取一个点权大于0的点,然后对于这个点bfs出去的路径小于k的点减去当前点的a[u],然后将a[i]加入到ans中
#include<bits/stdc++.h>
using namespace std;
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=b;i>=a;i--)
#define pb push_back
const int M=;
int deep[M],vis[M],a[M],b[M],k,n;
vector<int>g[M];
void dfs(int u,int f){
deep[u]=deep[f]+;
for(int i=;i<g[u].size();i++){
int v=g[u][i];
if(v!=f){
dfs(v,u);
}
}
}
bool cmp(int x,int y){
return deep[x]>deep[y];
}
struct node{
int val,st;
};
int bfs(int st){
queue<node>que;
node s;
s.val=st;
s.st=;
que.push(s);
memset(vis,,sizeof(vis));
int c=a[st];
while(!que.empty()){
node u=que.front();
vis[u.val]=;
a[u.val]-=c;
que.pop();
if(u.st!=k){
for(int i=;i<g[u.val].size();i++){
int v=g[u.val][i];
if(!vis[v]){
node p;
p.val=v;
p.st=u.st+;
que.push(p);
}
}
} }
return c;
}
int main(){ scanf("%d%d",&n,&k);
fo(i,,n)
scanf("%d",&a[i]);
fo(i,,n-){
int x,y;
scanf("%d%d",&x,&y);
g[x].pb(y);
g[y].pb(x);
}
dfs(,);
fo(i,,n)b[i]=i;
sort(b+,b++n,cmp);
int ans=;
fo(i,,n)
if(a[i]>)
ans+=bfs(i);
cout<<ans<<endl;
return ;
}
树形dp做法
dp[u][i]表示以u的子树中被选的点离u最近距离是i的最大权值和;
对当前节点,我们分取和不取的情况;
取的情况:那么当前点的子树对当前点的贡献肯定就是∑dp[v][k];
不取的情况:那么我们就既要保证子树之间的距离要大于k,又要满足子树对当前节点距离为i的贡献。若一个子树取了距离为i-1,那么就要保证其他子树取的距离都要大于k-i。
当平衡的时候我们得到一个式子k-(k-i+1) = i-1,所以要在k-i和i-1中取最大值,作为要对当前节点u做贡献的v的距离j,也就是dp[v][j]。
分析一下,当j取i-1的时候要求其他子树与当前节点u的距离要大于k-(i-1),因为在上面 j 已经取了(k-i)和(i-1)的最大值,所以不用考虑其他,直接把dp[v][j]加上去;
当 j 取k-i时,我们发现实际上,k-i一定比i-1更深,所以dp[v][k-1]<=dp[v][i-1],所以取值上虽然取的时深度为k-i深度的值,此时我们可以假想取的时i-1的位置,
所以就满足了距离为 i 的限制,接着,又因为只是要大于k而已,我们取的深度明显大于k一些,所以为了最大化答案,就取max(dp[v][i-1]-dp[v][j])。只是一个子树达到了 i-1 ,
这并不会影响俩俩子树之间距离大于k的事实
#include<bits/stdc++.h>
using namespace std;
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=b;i>=a;i--)
#define pb push_back
const int M=;
vector<int>g[M];
int n,k;
int a[M];
int dp[M][M];//dp[u][i]表示以u的子树中被选的点离u最近距离是i的最大权值和
void dfs(int u,int f){
for(int i=;i<g[u].size();i++){
int v=g[u][i];
if(v==f)
continue;
dfs(v,u);
}
//cout<<"!!"<<endl;
for(int i=n-;i>=;i--){
if(i==){//u不取的情况
for(int p=;p<g[u].size();p++){
int v=g[u][p];
if(v==f)
continue;
dp[u][i]+=dp[v][k];
}
dp[u][i]+=a[u];
}
else{
int j=max(i-,k-i);
int tot=,mx=;
for(int p=;p<g[u].size();p++){
int v=g[u][p];
if(v==f)
continue;
tot+=dp[v][j];
mx=max(mx,dp[v][i-]-dp[v][j]);
}
dp[u][i]=tot+mx;
}
dp[u][i]=max(dp[u][i],dp[u][i+]);
}
}
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
for(int x,y,i=;i<n;i++){
scanf("%d%d",&x,&y);
g[x].pb(y);
g[y].pb(x);
}
dfs(,);
printf("%d\n",dp[][]);
return ;
}
F. Maximum Weight Subset(贪心or树形dp解法)的更多相关文章
- Codeforces 1249F Maximum Weight Subset (贪心)
题意 在一颗有点权的树上,选若干个点,使得这些点两两距离大于k,且点权和最大 思路 贪心的取比较大的值即可 将所有点按照深度从大到小排序,如果当前点点权\(a[i]\)大于0,则将距离为k以内的所有点 ...
- Codeforces 1249 F. Maximum Weight Subset
传送门 设 $f[x][i]$ 表示 $x$ 的子树中,离 $x$ 最近的选择的节点距离为 $i$ 的合法方案的最大价值 设 $val[x]$ 表示节点 $x$ 的价值,首先有 $f[x][0]=va ...
- CF1249F Maximum Weight Subset
CF1249F Maximum Weight Subset 洛谷评测传送门 题目描述 You are given a tree, which consists of nn vertices. Reca ...
- 求树的最大独立集,最小点覆盖,最小支配集 贪心and树形dp
目录 求树的最大独立集,最小点覆盖,最小支配集 三个定义 贪心解法 树形DP解法 (有任何问题欢迎留言或私聊&&欢迎交流讨论哦 求树的最大独立集,最小点覆盖,最小支配集 三个定义 最大 ...
- 【CF1249F】Maximum Weight Subset(贪心)
题意:给定一棵n个点带点权的树,要求从中选出一个点集,使得这些点两两之间距离都大于K,求最大点权和 n,K<=2e2,1<=a[i]<=1e5 思路:树形DP显然可做,极限是n方,然 ...
- P2279 [HNOI2003]消防局的设立 贪心or树形dp
题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...
- bzoj 2067: [Poi2004]SZN【贪心+二分+树形dp】
第一问就是Σ(deg[u]-1)/2+1 第二问是二分,判断的时候考虑第一问的贪心规则,对于奇度数的点,两两配对之后一条延伸到上面:对于欧度数的点,两两配对或者deg[u]-2的点配对,然后一条断在这 ...
- Strategic game树形DP解法(Poj1463,Uva1292)
已经写过本题用二分图的做法,见这儿. 本题的图是一棵树,求最小点覆盖也可以用树形DP的做法. 定义状态f[0/1][u]表示以u为根的子树,u选取/不选最少需要选取多少点来覆盖. 显然 f[0][u] ...
- codeforces#1249F. Maximum Weight Subset(树上dp)
题目链接: http://codeforces.com/contest/1249/problem/F 题意: 一棵树的每个节点有个权值,选择一个节点集,使得任意点对的距离大于$k$ 求最大节点集权值, ...
随机推荐
- 日志处理中一些shell命令技巧
日志处理中一些shell命令技巧 阴差阳错的做的日志分析,前途未卜的这段日子,唯一还有点意思的可能就是手动的处理大量日志.总结一下. 日志文件的输入是动则几个G的文本.从N个这样的文件中得到一个列表, ...
- android studio 黑屏问题
AVD配置不对,打开AVD从新配置
- Redis主从复制以及主从复制原理
Redis 是一个开源的使用 ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的 API.从 2010年 3 月 15 日起,Redis 的开 ...
- UVA 10534 LCS变种题
求一个序列中 的2*n-1个数字 ,前n+1个数字为严格升序 后n+1个为严格降序,求最长的长度 一开始还没想清楚怎么解,其实就是一个LCS问题,从头到尾以及反序求一下LCS 由于 d[i]为包含了自 ...
- 最短路———Floyd算法
C - 六度分离 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Sta ...
- 72)MFC测试动态共享库
动态共享库: 首先我建立一个新的动态库: 然后不选择空项目了,因为我们普通的cpp文件 入口是main win32入口是winmain 那么这个动态库的入口在哪里 我们就是为了看一看: 出来这样 ...
- idea新建文件模板 (以xml文件为例)
https://blog.csdn.net/li1325169021/article/details/93158207 偷个懒
- uniapp 初始化项目
const baseUrl = 'http://10.92.1.17:6601/videoapi/'; //const baseUrl = '/videoapi/'; //对于 GET 方法,会将数据 ...
- Java集合(一)——Collection
集合概述 集合(Collections)是存储对象的容器.方便对多个对象的操作.存储对象,集合的作用就在这时显现了. 集合的出现就是为了持有对象.集合中可以存储任意类型的对象, 而且长度可变.在程序中 ...
- linux的vi编辑器中如何查找内容(关键字)
按下”/“键,这时在状态栏(也就是屏幕左下脚)就出现了 “/” 然后输入你要查找的关键字敲回车就可以了. 找到相关文字以后: (1)按下小写n,向下查找 (2)按下大写N,向上查找