题: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解法)的更多相关文章

  1. Codeforces 1249F Maximum Weight Subset (贪心)

    题意 在一颗有点权的树上,选若干个点,使得这些点两两距离大于k,且点权和最大 思路 贪心的取比较大的值即可 将所有点按照深度从大到小排序,如果当前点点权\(a[i]\)大于0,则将距离为k以内的所有点 ...

  2. Codeforces 1249 F. Maximum Weight Subset

    传送门 设 $f[x][i]$ 表示 $x$ 的子树中,离 $x$ 最近的选择的节点距离为 $i$ 的合法方案的最大价值 设 $val[x]$ 表示节点 $x$ 的价值,首先有 $f[x][0]=va ...

  3. CF1249F Maximum Weight Subset

    CF1249F Maximum Weight Subset 洛谷评测传送门 题目描述 You are given a tree, which consists of nn vertices. Reca ...

  4. 求树的最大独立集,最小点覆盖,最小支配集 贪心and树形dp

    目录 求树的最大独立集,最小点覆盖,最小支配集 三个定义 贪心解法 树形DP解法 (有任何问题欢迎留言或私聊&&欢迎交流讨论哦 求树的最大独立集,最小点覆盖,最小支配集 三个定义 最大 ...

  5. 【CF1249F】Maximum Weight Subset(贪心)

    题意:给定一棵n个点带点权的树,要求从中选出一个点集,使得这些点两两之间距离都大于K,求最大点权和 n,K<=2e2,1<=a[i]<=1e5 思路:树形DP显然可做,极限是n方,然 ...

  6. P2279 [HNOI2003]消防局的设立 贪心or树形dp

    题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...

  7. bzoj 2067: [Poi2004]SZN【贪心+二分+树形dp】

    第一问就是Σ(deg[u]-1)/2+1 第二问是二分,判断的时候考虑第一问的贪心规则,对于奇度数的点,两两配对之后一条延伸到上面:对于欧度数的点,两两配对或者deg[u]-2的点配对,然后一条断在这 ...

  8. Strategic game树形DP解法(Poj1463,Uva1292)

    已经写过本题用二分图的做法,见这儿. 本题的图是一棵树,求最小点覆盖也可以用树形DP的做法. 定义状态f[0/1][u]表示以u为根的子树,u选取/不选最少需要选取多少点来覆盖. 显然 f[0][u] ...

  9. codeforces#1249F. Maximum Weight Subset(树上dp)

    题目链接: http://codeforces.com/contest/1249/problem/F 题意: 一棵树的每个节点有个权值,选择一个节点集,使得任意点对的距离大于$k$ 求最大节点集权值, ...

随机推荐

  1. Python Email发送,通知业务完成

    Email 发送 #!/usr/bin/python # -*- coding: UTF-8 -*- import base64 import smtplib from email.mime.text ...

  2. jobs|ps|杀死nohup

    方法1:如果没有退出客户端界面,可以先通过 “jobs” 命令查看程序是否在运行,此时只有序号没有PID号:输入命令 “jobs -l” 会显示程序的PID号,然后通过 “kill -9 PID”杀死 ...

  3. DQL单表查询

    DQL数据查询语言数据查询关键字:select 对数据库关系表中的数据进行查询 创建数据库创建表格学生表(学号s_no,姓名s_name,班级s_classno,课程s_courseno) 班级表(班 ...

  4. POJ 1547:Clay Bully

    Clay Bully Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 8349   Accepted: 4711 Descri ...

  5. 刷题32. Longest Valid Parentheses

    一.题目说明 题目是32. Longest Valid Parentheses,求最大匹配的括号长度.题目的难度是Hard 二.我的做题方法 简单理解了一下,用栈就可以实现.实际上是我考虑简单了,经过 ...

  6. JAVA多线程的基础

    线程与进程的区别 1.线程与进程 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行.也可以把它理解为代码运行的上下文.所 ...

  7. try,catch,finally尝试(一个程序块多个catch)

    曾学过c++,但是对这些异常捕捉不是很了解,通过别的编程语言了解 public class newclass { public static void main(String[] args) { tr ...

  8. SQL语句、PL/SQL块和SQL*Plus命令之间的区别

    SQL语句.PL/SQL块和SQL*Plus命令之间的区别   原文链接:https://blog.csdn.net/liuzhushiqiang/article/details/12320941 在 ...

  9. SQL基础教程(第2版)第2章 查询基础:2-1 SELECT语句基础

    ● 通过指定DISTINCT可以删除重复的行.● 为列设定显示用的别名. ■列的查询 通过 SELECT 语句查询并选取出必要数据的过程称为查询(query). 该 SELECT 语句包含了 SELE ...

  10. Spark核心算子

    Spark RDD: Transformation Meaning map(func) 返回一个新的分布式数据集,该数据集是通过将源的每个元素传递给函数func处理形成的. filter(func) ...