Luogu P3942 将军令
这是一类比较普遍的问题,即
给定一颗无权树,放置一个点可以覆盖距离它不超过k的节点(0 <= k <= n),问最少放置多少点可以将树上所有点全部覆盖
考虑贪心:
f[u][0] 距u最近的放置点到u距离 ; f[u][1] 距u最远的未覆盖点到u距离
转移易得
f[u][0] = inf,f[u][1] = -inf; f[u][0] = min(f[u][0],f[v][0] + 1); f[u][1] = max(f[u][1],f[v][1] + 1);
考虑到:
if(f[u][0] > k) f[u][1] = max(f[u][1],0); if(f[u][0] + f[u][1] <= k) f[u][1] = -inf; if(f[u][1] == k) ans++,f[u][0] = 0,f[u][1] = -inf;
要赋值成-inf是要不对之后的转移产生影响(其实考虑定义也可以,但是这里不能随便用0
最后特判根d的f[1]是否有值即可
现在,考虑问题的加强版:
https://www.luogu.org/problem/P3523
只需记录is[i]代表i需要被覆盖,易得
if(is[u] && f[u][0] > k) f[u][1] = max(f[u][1],0);
三倍经验(滑稽
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<vector> using namespace std; typedef long long ll; #define O(x) cout << #x << " " << x << endl; #define clr(a) memset(a,0,sizeof(a)); #define B cout << "breakpoint" << endl; #define pii pair<int,int> #define mp make_pair #define fi first #define se second inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 3e5 + 5; const int inf = 99999999; struct egde { int to,next; }e[maxn << 1]; int fir[maxn],alloc; void adde(int u,int v) { e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; swap(u,v); e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; } int f[maxn][2]; int n,m,ans,k; // f[u][0] 距u最近的放置点到u距离 ; f[u][1] 距u最远的未放置点到u距离 bool is[maxn]; void dfs(int u,int fa) { f[u][0] = inf,f[u][1] = -inf; for(int i = fir[u];i;i = e[i].next) { int v = e[i].to; if(v == fa) continue; dfs(v,u); f[u][0] = min(f[u][0],f[v][0] + 1); f[u][1] = max(f[u][1],f[v][1] + 1); } if(is[u] && f[u][0] > k) f[u][1] = max(f[u][1],0); if(f[u][0] + f[u][1] <= k) f[u][1] = -inf; if(f[u][1] == k) ans++,f[u][0] = 0,f[u][1] = -inf; } int main() { n = read(); k = 2; for(int i = 2;i <= n;i++) { int u = read(); adde(u,i); } /*if(k == 0) { printf("%d",n); return 0; }*/ for(int i = 1;i <= n;i++) is[i] = 1; dfs(1,0); if(f[1][1] >= 0) ans++; printf("%d",ans); } /* 6 0 0 1 2 1 3 1 4 4 5 4 6 */