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