zoukankan      html  css  js  c++  java
  • P2279 消防局的设立(贪心+dp)

    题目链接:传送门

    题目大意:

      给定一棵树(N个基地N-1条边);

      用半径为2的消防局覆盖这N个基地,问最小的消防局数量。

      (树上距离为k的最小覆盖问题)

    思路:

      每次贪心地找到不被覆盖的最深的一个节点,在它的祖父处放一个消防局。

      这个消防局所在位置即能将这个节点覆盖到的离它最远的点。

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAX_N = 1e3 + 5;
    
    int N;
    vector <int> Edge[MAX_N];
    int dep[MAX_N], fa[MAX_N];
    bool vis[MAX_N];
    
    int findlower()
    {
        int lower = 0, ind = 0;
        for (int i = 1; i <= N; i++) {
            if (!vis[i] && dep[i] > lower) {
                lower = dep[i];
                ind = i;
            }
        }
        return ind;
    }
    
    void update(int x)
    {
        x = fa[fa[x]];
        for (int i = 0; i < (int)Edge[x].size(); i++) {
            int y = Edge[x][i];
            vis[y] = true;
            for (int j = 0; j < (int)Edge[y].size(); j++) {
                int z = Edge[y][j];
                vis[z] = true;
            }
        }
    }
    
    int solve()
    {
        memset(vis, false, sizeof vis);
        int ans = 0;
        int cur = findlower();
        while (cur) {
            update(cur);
            ans++;
            cur = findlower();
        }
        return ans;
    }
    
    void build(int x)//不妨把编号为1的点当作根节点
    {
        for (int i = 1; i <= N; i++) {
            dep[i] = -1;
            fa[i] = i;
        }
        dep[x] = 1;
        queue <int> Q;
        Q.push(x);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            for (int i = 0; i < (int)Edge[u].size(); i++) {
                int v = Edge[u][i];
                if (dep[v] < 0) {
                    dep[v] = dep[u] + 1;
                    fa[v] = u;
                    Q.push(v);
                }
            }
        }
    }
    
    int main()
    {
        cin >> N;
        for (int u = 2; u <= N; u++) {
            int v;
            cin >> v;
            Edge[u].push_back(v);
            Edge[v].push_back(u);
        }
        int ans = N;
        build(1);
        ans = min(ans, solve());
        cout << ans << endl;
        return 0;
    }
    View Code

      前面有点想多了,因为题目中给出的ai < i,所以不需要build直接拿题目中给的树来用就好了。。

      不过也无伤大雅。

      然后是膜大佬学到的代码:

      求树上距离为k的最小覆盖都可以这样做:

      (时间复杂度为O(N * k))

    #include <bits/stdc++.h>
    
    using namespace std;
    const int MAX_N = 1e3 + 5;
    const int INF = 0x3f3f3f3f;
    
    struct Node{
        int dep, ind;
        Node(int d = 0, int i = 0) : dep(d), ind(i) {}
        bool operator < (const Node& x) const {
            return dep > x.dep;
        }
    }nodes[MAX_N];
    
    int fa[MAX_N], dis[MAX_N];
    
    int main()
    {
        int N;
        cin >> N;
        nodes[1] = Node(0, 1);
        fa[1] = 1;
        dis[1] = INF;
        for (int i = 2; i <= N; i++) {
            scanf("%d", fa+i);
            dis[i] = INF;
            nodes[i].ind = i;
            nodes[i].dep = nodes[fa[i]].dep + 1;
        }
        sort(nodes+1, nodes+N+1);
        int ans = 0;
        for (int i = 1; i <= N; i++) {
            int u = nodes[i].ind;
            int v = fa[u];
            int w = fa[v];
            if (dis[u] > 2 && dis[v] > 1 && dis[w] > 0) {
                ans++;
                dis[u] = 2;
                dis[v] = min(dis[v], 1);
                dis[w] = min(dis[w], 0);
                dis[fa[w]] = min(dis[fa[w]], 1);
                dis[fa[fa[w]]] = min(dis[fa[fa[w]]], 2);
            }
        }
        cout << ans << endl;
        return 0;
    }
    View Code

      

  • 相关阅读:
    错误及异常处理-[PathTooLongException]指定的路径或文件名太长
    在线颜色转换器
    文件被锁定的原因
    EF6官方文档
    我关注的
    "此实现不是 Windows 平台 FIPS 验证的加密算法的一部分"解决办法
    Rsync Error set gid failed rsync error
    转载——EntiyFrameWork教程
    Word 出现“因为没有打开的文档,所以这一命令无效”的错误
    Winsock网络编程笔记:基于UDP的Client
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/9807973.html
Copyright © 2011-2022 走看看