基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
 收藏
 取消关注
夹克老爷逢三抽一之后,由于采用了新师爷的策略,乡民们叫苦不堪,开始组织起来暴力抗租。
夹克老爷很愤怒,他决定派家丁常驻村中进行镇压。

诺德县 有N个村庄,编号0 至 N-1,这些村庄之间用N - 1条道路连接起来。

家丁都是经过系统训练的暴力机器,每名家丁可以被派驻在一个村庄,并镇压当前村庄以及距离该村庄不超过K段道路的村庄。
夹克老爷一贯奉行最小成本最大利润的原则,请问要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?


Input
第1行:2个数N, K中间用空格分隔(1<= N <= 100000, 0 <= K <= N)。
之后N-1行:每行2个数S, E中间用空格分隔,表示编号为S的村庄同编号为E的村庄之间有道路相连。(0 <= S, E < N)。
Output
输出一个数说明要实现对全部村庄的武力控制,夹克老爷需要派出最少多少名家丁?
Input示例
4 1
0 1
0 2
0 3
Output示例
1

官方题解:树形DP,贪心思想,从叶子节点向上,能不放就不放,到了k长就放一个。

后序遍历,记录不同子树上传的状态,子树状态记录为该子树可以向上管理的(缺少的用负数)

可能A子树放置的家丁可以把B子树的村庄全部覆盖,这样就可以节约家丁数了。

min_length = min(dp[child])

max_length = max(dp[child])

if(min_length <= -K) {

    ++result;

    dp[cur_idx] = K;   //子树需要暴力支援深度达到K了,必须在当前位置放置一个家丁,并向上提供K的暴力输出

} else if(max_length + min_length > 0) {

    dp[cur_idx] = max_child - 1;      //有一个子树放置的家丁能够把全部其他需要镇压的村庄都覆盖

} else {

    dp[cur_idx] = min_child - 1;      //继续向上级要求暴力支持

}



最后如果root的状态小于0要额外多放一个。

这个题目真的挺好玩的,把这n个村庄n-1个连接想象成是一个树,然后记录每一个节点缺少的级别,当到达了k个级别的时候就要加上一个家丁,此时这个节点缺少的级别是正的k,因为它要开始照顾到它的兄弟子树了。

手动扩栈扩栈也是头一次。。。

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#pragma warning(disable:4996)
using namespace std; #define inf 0x3f3f3f3f int res;
int n, k;
int s, e;
int used[100050];
int dp[100050];
vector<int>node[100050]; void dfs(int x)
{
used[x] = 1;
int minn = inf;
int maxn = -inf;
int size = node[x].size(); int i;
for (i = 0; i < size; i++)
{
int temp = node[x][i];
if (used[temp] == 0)
{
dfs(temp);
minn = min(minn, dp[temp]);
maxn = max(maxn, dp[temp]);
}
}
if (minn == inf)
{
dp[x] = -1;
}
else if(minn<=-k)
{
res++;
dp[x] = k;
}
else if (maxn + minn > 0)
{
dp[x] = maxn - 1;
}
else
{
dp[x] = minn - 1;
}
used[x] = 0;
} int main()
{
//freopen("i.txt", "r", stdin);
//freopen("o.txt", "w", stdout); int i;
scanf("%d%d", &n, &k); for (i = 1; i <= n - 1; i++)
{
scanf("%d%d", &s, &e);
s++;
e++;
node[s].push_back(e);
node[e].push_back(s);
}
if (k == 0)
{
printf("%d", n);
return 0;
}
dfs(1); if (dp[1] < 0)
{
res++;
}
printf("%d", res);
//system("pause");
return 0;
}

最新文章

  1. oracle 和c3p0 数据库的Time_Wait 过多问题的一个解决方案。
  2. #研发解决方案#discache-分布式缓存查询与管理系统
  3. [poj2182] Lost Cows (线段树)
  4. 不可或缺 Windows Native (11) - C++: hello c++, C++ 与 C语言的区别小介
  5. 餐厅点餐系统app第二天
  6. 虚拟机VirtualBox中centos6.5网络设置
  7. jQuery滚动监听插件Waypoints
  8. IEEE二进制浮点数算术标准(IEEE 754)
  9. Android模拟器的文件目录介绍
  10. 【总结】在VirtualBox上面安装Mac的注意事项
  11. 【C语言】字符串模块
  12. SpringCloud-Eureka注册与发现
  13. wireshark 抓包过滤器使用
  14. react初入门
  15. Linux C 编程
  16. 创建触发器(trigger)
  17. iOS 线上版本图片资源格式的问题导致的闪退
  18. 查看服务器系统资源(cpu,内容)利用率前几位的进程的方法
  19. 读取本地图片 BitmapImage
  20. Mysql 8 常用命令测试

热门文章

  1. ip命令规范
  2. LockSupport源码分析
  3. day5-1继承
  4. linux--用户管理--useradd
  5. Gof 设计模式
  6. 【转】CentOS6开启BBR加速
  7. java 中类加载器
  8. Python内置模块-logging
  9. 说说maven依赖冲突,依赖调解,依赖传递和依赖范围
  10. linux系统登陆过程