• 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
  • 相关阅读:
    学习java集合LinkedHastSet
    学习java,equals方法
    学习java,入门语言java的感概
    学习java哈希值,java入门编程语言
    学习java集合HashSet
    学习java集合set集合
    学习java集合LinkedList
    学习java集合Arraylist
    学习java集合list集合
    学习Java数据结构(入门选Java)
  • 原文地址:https://www.cnblogs.com/LM-LBG/p/11594009.html
Copyright © 2020-2023  润新知