zoukankan      html  css  js  c++  java
  • 洛谷2279:消防局的设立

    洛谷2279:消防局的设立

    题意:

    • 给定一棵树,树上的某些节点设立消防局,这个消防局可以覆盖距离不超过2的节点。
    • 问有最少有多少个消防局可以覆盖整棵树。

    数据范围:

    • (1leq nleq 1000)

    思路:

    • 树形(dp)
    • (f(i,state))表示节点(i)(state)状态下表示最小的消防站个数。
    • (f(i,0))表示选择(i)为消防局。
    • (f(i,1))表示至少选了一个(i)的一个儿子为消防局。
    • (f(i,2))表示至少选了一个(i)的孙子为消防局。
      • 这三种情况(i)可以覆盖自己。
    • (f(i,3))表示(i)的所有儿子节点一定被消防局覆盖。
    • (f(i,4))表示(i)的所有孙子节点一定被消防局覆盖。
    • 转移方程:
      • (f(i,0)=1+sum min(f(j,0...4)))
        • 解释:由于(i)为消防站儿子和孙子就无所谓了,因此从0~4中寻找一个(min)来转移,最后(+1)(自己的开销)。这里(j)对应的是儿子。
      • (f(i,1)=min(f(k,0)+sum_{j!=k}min(f(j,0...3)))
        • 解释:(f(i,1))表示至少选了一个(i)的儿子为消防局,那么不能保证所有的孙子都能被覆盖,只能保证父亲和所有兄弟被覆盖到,同时需要(i)的孙子一定要被全部覆盖。(i)的孙子被全部覆盖,状态0~3满足。这里(k)对应的是其中一个儿子,(j)对应的是除了(k)以外的其他儿子。
      • (f(i,2)=min(f(k,1)+sum_{j!=k}min(f(j,0...2)))
        • 解释:选了一个孙子,那么所有的儿子应该被全部覆盖掉,儿子被覆盖的状态对应0~2。这里(k)对应的是其中一个儿子,(j)对应的是除了(k)以外的其他儿子。
      • (f(i,3)=sum min(f(j,0...2)))
        • 解释:要让所有的儿子一定被覆盖,那么儿子的0~2状态都符合条件。
      • (f(i,4)=sum min(f(j,0...3)))
        • 解释:孙子全部被覆盖,那么儿子的0~3状态都符合条件,所以取个(min)
    • 发现了所有的状态都是0~?这样的形式,所以令(f(i,j))表示(min(f(i,0...k)))
    • 因此有:
      • (f(i,0)=1+sum f(j,4)).
      • (f(i,1)=f(i,4)+min(f(j,0)-f(j,3))).
        • 选一个儿子作为消防局,需要保证所有孙子应该被覆盖,所以加上(f(i,4))。对于(f(i,4)),选那个儿子处于状态0~3,但是要把他转变为只选择自己,所以取(f(j,0)-f(j,3))
      • (f(i,2)=f(i,3)+min(f(j,1)-f(j,2))).
        • 选一个孙子作为消防局,需要保证所有儿子被覆盖,所以加上 (f(i,3))。对于(f(i,3)),儿子处于(f(j,2))状态,但是需要将一个儿子变为0~1状态保证父亲节点被覆盖,所以取(f(j,1)-f(j,2))
      • (f(i,3)=sum f(j,2)).
      • (f(i,4)=sum f(j,3)).
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1000 + 10;
    const int INF = 0x3f3f3f3f;
    int a[maxn], n;
    bool G[maxn][maxn];
    int f[maxn][10];
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 2, x; i <= n; i++)
        {
            scanf("%d", &x);
            G[x][i] = 1;
        }
        for(int i = n, x1, x2; i >= 1; i--)
        {
            x1 = x2 = INF;
            f[i][0] = 1;
            for(int j = 1; j <= n; j++)
            {
                if(G[i][j])
                {
                    f[i][0] += f[j][4];
                    f[i][3] += f[j][2];
                    f[i][4] += f[j][3];
                    x1 = min(x1, f[j][0]-f[j][3]);
                    x2 = min(x1, f[j][1]-f[j][2]);
                }
            }
            f[i][1] = f[i][4] + x1;
            f[i][2] = min(f[i][3]+x2, min(f[i][0], f[i][1]));
            f[i][3] = min(f[i][2], f[i][3]);
            f[i][4] = min(f[i][3], f[i][4]);
        }
        cout << f[1][2] << endl;
        return 0;
    }
    
    
  • 相关阅读:
    记录一次 Linux crontab 执行django 脚本 失败 的经历和解决办法
    python3 使用 django-xadmin 遇到的许多坑
    简要说明 django restframework 的交互式文档
    No application found. Either work inside a view function or push an application context.
    解决Docker容器内访问宿主机MySQL数据库服务器的问题
    《计算机网络自顶向下方法-第七版》第三章总结
    《计算机网络自顶向下方法-第七版》第七章总结
    《计算机网络自顶向下方法-第七版》第二章总结
    《计算机网络自顶向下方法-第七版》第一章总结
    深入理解Docker容器执行引擎runC
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12049773.html
Copyright © 2011-2022 走看看