51nod 1378 夹克老爷的愤怒(树形DP+贪心)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378

大致题意:

一棵1e5节点的树,安放某些位置,一个位置可以控制距他的距离不超过K的所有节点, 输入树和K,求控制全图(所有节点)需要安放最少的个数

思路:

假如是线性结构,一定是从边界开始每距离2k安放一个,然后最后正好或者再放置一个,这个贪心思路所有人都会。

当是树形结构时,仍然用那个贪心,显然安放的位置越靠近根节点控制的其他节点数越多,所以这里必须从枝叶当作开始的边界,所以可以后序遍历,每到达必须要放的位置才放一个,用dp[i],记录i节点可以向上掌控多少个节点,欠掌控时用负数,这样对每个节点,根据它的所以子节点的dp中的max,和min就 可以进行状态转移

当根节点的dp<0时,额外多放置一个

特别的,当k等于0 输出n


//#pragma comment(linker, "/STACK:1024000000,1024000000")

#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
#define rep(i,n) for ( int i=0; i< int(n); i++ )
using namespace std;
typedef long long ll;
#define X first
#define Y second
typedef pair<int,int> pii;

template <class T>
inline bool RD(T &ret) {
    char c; int sgn;
    if (c = getchar(), c == EOF) return 0;
    while (c != '-' && (c<'0' || c>'9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
template <class T>
inline void PT(T x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9) PT(x / 10);
    putchar(x % 10 + '0');
}

const int N = 1e5+100;
int dp[N];
int n,k;

struct Edge{
        int v,nxt ;
        Edge(int v =0,int nxt = 0) :v(v), nxt(nxt){}
}es[N*2];
int ecnt;
int head[N];
inline void add_edge(int u,int v){
        es[ecnt] = Edge( v , head[u] );
        head[u] = ecnt++;
        es[ecnt] = Edge( u , head[v] );
        head[v] = ecnt++;
}
const int inf = 0x3f3f3f3f;
int ans = 0;
void dfs(int u, int fa){
        int minn = inf, maxn = -inf;
        for(int i = head[u]; ~i; i = es[i].nxt){
                int v = es[i].v;
                if( v == fa ) continue;
                dfs(v,u);
                minn = min( minn, dp[v] );
                maxn = max( maxn, dp[v] );
        }
        if( minn == inf) dp[u] = -1;
        else if( minn <= -k) {
                ans ++;
                dp[u] = k;
        }else if( minn+maxn > 0 ) dp[u] = maxn-1;
        else dp[u] = minn-1;

}
int main(){

        while( ~scanf("%d%d",&n,&k)){
                ans = ecnt = 0;
                memset(dp,0,sizeof(dp));
                memset(head,-1,sizeof(head));
                REP(i,n-1){
                        int u, v;
                        RD(u),RD(v);
                        u ++, v++;
                        add_edge( u, v);
                }
                if( k == 0 ) printf("%d\n",n);
                else{
                        dfs(1,-1);
                        if( dp[1] < 0 ) ans++;
                        printf("%d\n",ans);
                }
        }
}

夹克老爷逢三抽一之后,由于采用了新师爷的策略,乡民们叫苦不堪,开始组织起来暴力抗租。

夹克老爷很愤怒,他决定派家丁常驻村中进行镇压。

诺德县 有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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-18 12:45:59

51nod 1378 夹克老爷的愤怒(树形DP+贪心)的相关文章

[51nod] 1378 夹克老爷的愤怒 #树形DP

1378 夹克老爷的愤怒 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 夹克老爷逢三抽一之后,由于采用了新师爷的策略,乡民们叫苦不堪,开始组织起来暴力抗租. 夹克老爷很愤怒,他决定派家丁常驻村中进行镇压. 诺德县 有N个村庄,编号0 至 N-1,这些村庄之间用N - 1条道路连接起来. 家丁都是经过系统训练的暴力机器,每名家丁可以被派驻在一个村庄,并镇压当前村庄以及距离该村庄不超过K段道路的村庄. 夹克老爷一贯奉行最小成本最大利润的原则,请问要实现对全部村庄

51nod 1378 夹克老爷的愤怒(树型dp+贪心)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378 题意: 思路:要想放得少,尽量放在叶子节点处,叶子节点处点比较多. 从叶子节点开始往上回溯,到第k个点时就放置一名家丁,用dp[x]来记录状态,若为负,则表示该节点及其子树所需要家丁的最远距离,若为正,则表示该节点及其子树中家丁还能镇压的最大距离. 1 #include<cstdio> 2 #include<cstring> 3 #include&l

51Nod 1378 夹克老爷的愤怒

Description 一棵树,可以进行染色,被染色的点可以控制与它距离不超过 \(k\) 的所有点,问控制整棵树最少需要染几个点. Sol 贪心. 记录一下最深的未染色点和最浅的染色点,判断一下能否在子树中就完成,不能的话就把权值赋成最深未染色点深度+1,能的话就赋成染色点深度+1. 需要特判一下根. Code #include<cstdio> #include<vector> #include<ctime> #include<cstdlib> #incl

51nod 1380 夹克老爷的逢三抽一 堆 脑洞题

51nod 1380 夹克老爷的逢三抽一堆 脑洞题 题意 n个人围成一圈 然后每次可以选一个人,得到他的分数,然后他与他相邻的两个人出圈 总共选 n/3次, 保证n是3的倍数 题解 这道怎么说呢,应该比较巧妙吧,你开一个优先队列,大根堆,每次选择优先队列中最大的数,然后把他左右两个数删掉,比如 A B C 删掉 B ,那么就把 A+C-B 加入优先队列中,这其实就是相当于提供了一个后悔的机会,就像网络流中的反向边,如果在选中这个点的话,就相当于 B+(A+C-B) 然后就相当于 B 这个点 不选

Codeforces 77C 树形dp + 贪心

题目链接:点击打开链接 题意: 给定n个点, 每个点的豆子数量 下面是一棵树 再给出起点 每走到一个点,就会把那个点的豆子吃掉一颗. 问:回到起点最多能吃掉多少颗豆子 思路:树形dp 对于当前节点u,先把子节点v都走一次. 然后再往返于(u,v) 之间,直到u点没有豆子或者v点没有豆子. dp[u] 表示u点的最大值.a[u] 是u点剩下的豆子数. #include <cstdio> #include <vector> #include <algorithm> #inc

POJ 2057 The Lost House 经典树形DP+贪心

题意:链接 方法:树形DP+贪心 解析:这是一道好题. 好首先要明确这题求的是什么? 名义上是期望值,而实际上就是找一条路径.什么路径呢?从根节点走遍所有的叶子节点所花费步数最短的路径. 明确了题意后该怎么做呢? 首先看我们需要什么? 目前有个根节点,我们需要知道从他向一个分支走,失败步数是多少,成功步数是多少? 那么怎么维护我们需要的东西呢? 首先我们先给他们起个名:suc,fai; 其次再给一个节点的叶子节点的个数起个名:son 起名完事之后我们就要更新了. 先谈叶子节点,显然叶子节点的su

一道树形DP+贪心题——FramCraft

题目大意: mhy住在一棵有n个点的树的1号结点上,每个结点上都有一个妹子. mhy从自己家出发,去给每一个妹子都送一台电脑,每个妹子拿到电脑后就会开始安装zhx牌杀毒软件,第i个妹子安装时间为. 树上的每条边mhy能且仅能走两次,每次耗费1单位时间.mhy送完所有电脑后会回自己家里然后开始装zhx牌杀毒软件. 卸货和装电脑是不需要时间的. 求所有妹子和mhy都装好zhx牌杀毒软件的最短时间. 分析一下题意: 树上的每条边mhy能且仅能走两次,这个有什么用? 很有用.自己想想!我不说了,模拟模拟

51Nod 1380 夹克老爷的逢三抽一

Description 一开始有一个环,可以选择删除一个元素获得他的权值,同时删除与它相邻的两个元素,其他元素重新形成环,问能获得的最大价值. Sol 堆+贪心. 一开始从堆中加入所有元素,然后取出一个元素之后,加入他两边的元素之和-该位置的权值,并把左右两点删除. 一直到取出 \(\frac {n} {3}\) 个元素即可,左右元素可以用链表维护. 这样取出一个元素了以后可以进行反悔的操作,获得另外两个权值. xyx大爷说只要不相邻那么元素个数使得他必然有一种合法的删除方案. Code #in

BZOJ 2097 Exercise 奶牛健美操 二分答案+树形DP+贪心

题目大意:给定一棵树,可以删掉k条边,求删掉后森林中所有树直径的最大值的最小值 最大值最小,典型的二分答案 此题我们二分树的直径,每次二分DFS一次,对于每个节点统计出所有子树删边后的dis,排序,贪心删掉最大的,直到最大的两个子树相加不会超过二分的答案为止 时间复杂度O(nlog^2n) 老子的二分居然写挂了...桑不起啊啊啊啊 #include<cstdio> #include<cstring> #include<iostream> #include<algo