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

你可能感兴趣的:(51nod 1378 夹克老爷的愤怒(树形DP+贪心))