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
*/
View Code

 

posted on 2019-09-26 20:01  L_M_A  阅读(128)  评论(0编辑  收藏  举报

导航