zoukankan      html  css  js  c++  java
  • LOJ-皇宫看守

    题目

    题目链接

    测试得分:  100

    主要算法 :  树型DP、点的最小覆盖,二分图(匈牙利算法)

    题干:

       点加权的最小覆盖

    应试策略:

      题目说的很清楚,用最少的点覆盖所有的点。题目给出的是个树,所以可以用动态规划来解决。
      给出如下定义:
      F[i,0]表示i点不放,i可以被父亲节点观察到;
      F[i,1]表示i点不放,i可以被儿子节点观察到;
      F[i,2]表示i点放,在i处设置警卫;
      转移如下:
        1、由F[i,0]定义可知,设j为i的儿子节点,儿子节点都需要被观察到,但由于根节点i不放,所以儿子必须保证能被观察到,即F[j][1],F[j][2],所以我们需要枚举必须放置的儿子节点,即下:
          F[i,0] = ∑(min(F[j][1],F[j,2]))}
            其中i为枚举儿子节点

        2、由F[i,1]定义可知,i的儿子结点中一定有一个结点有直接警卫,其它儿子节点必须都要被观察到,即下:
          F[i,1] =min(∑(min(F[j,1],F[j,2])+F[k,2])
            其中k为枚举的必放的儿子节点,j为除了k之外的儿子节点
        3、由F[i,2]定义可知,i点放置了守卫,所以对于每个儿子节点都能被观察到,取F[j,0],F[j,1],F[j,2]最小值即可,即下:
          F[i,2] = min(F[j,0],F[j,1],F[j,2])
            j是i的儿子节点

      代码

    /*题目说的很清楚,用最少的点覆盖所有的点。题目给出的是个树,所以可以用动态规划来解决。
        给出如下定义:
            F[i,0]表示i点不放,i可以被父亲节点观察到;
            F[i,1]表示i点不放,i可以被儿子节点观察到;
            F[i,2]表示i点放,在i处设置警卫;
        转移如下:
        1、由F[i,0]定义可知,设j为i的儿子节点,儿子节点都需要被观察到,但由于根节点i不放,所以儿子必须保证能被观察到,即F[j][1],F[j][2],所以我们需要枚举必须放置的儿子节点,即下:
              F[i,0] = ∑(min(F[j][1],F[j,2]))}
                其中i为枚举儿子节点
    
        2、由F[i,1]定义可知,i的儿子结点中一定有一个结点有直接警卫,其它儿子节点必须都要被观察到,即下:
              F[i,1] =min(∑(min(F[j,1],F[j,2])+F[k,2])  
                其中k为枚举的必放的儿子节点,j为除了k之外的儿子节点
        3、由F[i,2]定义可知,i点放置了守卫,所以对于每个儿子节点都能被观察到,取F[j,0],F[j,1],F[j,2]最小值即可,即下:
              F[i,2] = min(F[j,0],F[j,1],F[j,2]) 
                  j是i的儿子节点*/
    
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define FORa(i,s,e) for(int i=s;i<=e;i++)
    #define FORs(i,s,e) for(int i=s;i>=e;i--)
    
    using namespace std;
    const int N=1500,M=1500,INF=2147483647;
    int n,m,root,num_edge,head[N+1],a[N+1],f[N+1][3];
    /*f[u][0]表示的是结点u可以被父亲看到的安排的u为树根的子树安排的最少的警卫数
     f[u][1]表示的是结点u可以被儿子看到的安排的u为树根的子树安排的最少的警卫数
     f[u][2]表示的是结点u上安排警卫时的u为树根的子树安排的最少的警卫数
    */
    struct Edge{
        int next,to;
    }edge[2*M+2]; 
    void Add_edge(int from,int to) {edge[++num_edge]=(Edge){head[from],to},head[from]=num_edge;}
    inline int min(int fa,int fb){return fa<fb?fa:fb;}
    void Dp(int u,int fa)
    {
        int d=INF;
        for(int i=head[u];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(v!=fa)
            {
                Dp(v,u);
                f[u][0]+=min(f[v][1],f[v][2]);
                f[u][1]+=min(f[v][1],f[v][2]);
                d=min(d,f[v][2]-min(f[v][1],f[v][2]));
                f[u][2]+=min(f[v][0],min(f[v][1],f[v][2]));
            }
        }
        f[u][1]+=d,f[u][2]+=a[u];
        /*状态转移方程
            当点u可以被父亲看到的安排的u为树根的子树安排的最少的警卫数为保证子结点能够全部观察到,则为min(f[v][1],f[v][2])的和
             当点u可以被儿子看到的安排的u为树根的子树安排的最少的警卫数为保证子结点能够全部观察到,则至少有一个儿子结点必须要选,F[i,0] = min{∑(min(F[j][0],F[j,2]))+F[k,2]}
            当点u上安排警卫时的u为树根的子树安排的最少的警卫数为儿子结点的三者的min,F[i,2] = min(F[j,0],F[j,1],F[j,2]) 
        */ 
    }
    int main()
    {
        int from,to,fcnt;
        scanf("%d",&n);
        FORa(i,1,n)
        {
            scanf("%d",&from),scanf("%d%d",&a[from],&fcnt);
            FORa(j,1,fcnt) scanf("%d",&to),Add_edge(from,to),Add_edge(to,from);
        }
        root=1,Dp(root,0);
        printf("%d",min(f[root][1],f[root][2]));
        return 0;
    }
    /*6
    1 30 3 2 3 4
    2 16 2 5 6
    3 5 0
    4 4 0
    5 11 0
    6 5 0*/

    总结:

      1.确定建立模型

      2.构建知识架构,模型体系

    题目说的很清楚,用最少的点覆盖所有的点。题目给出的是个树,所以可以用动态规划来解决。
         给出如下定义:
    F[i,0]表示i点不放,且以i为根节点的子树(包括i节点)全部被观察到;
    F[i,1]表示i点不放,且以i为根节点的子树(可以不包括i节点)全部被观察到;
    F[i,2]表示i点放,且以i为根节点的子树全部被观察到;
         转移如下:
    1、由F[i,0]定义可知,设j为i的儿子节点,至少要有一个i的儿子节点是放置守卫的,其余的儿子节点可放可不放,但由于根节点i不放,所以其余的儿子节点如果不放的话,必须保证能被观察到,即F[j][0];所以我们需要枚举必须放置的儿子节点,即下:

      F[i,0] = min{∑(min(F[j][0],F[j,2]))+F[k,2]}

    其中k为枚举的必放的儿子节点,j为除了k之外的儿子节点


    2、由F[i,1]定义可知,i可以被观察到也可以不被观察到,但儿子节点必须都要被观察到,即下:

      F[i,1] =∑(min(F[j,0],F[j,2])) 

      j是i的儿子节点


    3、由F[i,2]定义可知,i点放置了守卫,所以对于每个儿子节点都能被观察到,取F[j,0],F[j,1],F[j,2]最小值即可,即下:
      F[i,2] = min(F[j,0],F[j,1],F[j,2]) j是i的儿子节点

    对于叶节点i,F[i,0] = F[i,2] = data[i],F[i,1] = 0;

    讲得已经十分详细了,剩下自己解决吧。

  • 相关阅读:
    反射 元类
    多态
    封装
    继承
    面向基础
    包 logging模块 hashlib模块 openpyxl 深浅拷贝
    常用模块
    re模块(正则表达式)
    模块 导入方式 软件开发目录规范
    第 3 章 镜像
  • 原文地址:https://www.cnblogs.com/SeanOcean/p/11314323.html
Copyright © 2011-2022 走看看