Luogu P3942 将军令

Posted lm-lbg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

以上是关于Luogu P3942 将军令的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P3942 将军令

P3942 将军令

luogu3942将军令

贪心P3942 将军令 && P2279 消防局的设立

将军令

「Luogu」2704炮兵阵地