• hdu5290树形dp


    题意 给了n个点的数 每个点有一个w[i]权值,如果你选择了i这个点那么距离i这个点距离为w[i]的点将被除去,最后问 选则尽量少的点把这n个点全部删除

    1<=n<=100000, 0<=w<=100,

    down[i][j]表示以i为根节点的树 在他的子树中在距离他 j距离 范围内存在至少一个点没有被除去所选择的最少点数

    up[i][j] 表示以i为根的树 他的子树全部都被除去,并且距离他为j的其他点可被除去 所选择的最小点数

    考虑状态转移

    如果第i个点不选

       那么 

           j=0时 

              down[i][0]=sigma(up[v][0]){v为i的孩子}

              up[i][0] =min(up[i][0], up[v][1]+down[i][0]-up[v][0]){v为i的孩子}

           j!=0的时候 

             down[i][j]=down[i][j]+down[v][j-1](v为i的孩子)

             up[i][j]=min(up[i][j],up[v][j+1]+down[i][j]-down[v][j-1]){v为i的孩子 , 自然你也可以在他的孩子中在j范围内取更多的点,但是好好想想这样是没有必要的}

    选了这个点

           那么up[i][j]=min( up[i][j] , Sigma(G[v][w[i]-1]) ) {v为i的孩子,自然也可以选择更进的点 但是也是没有必要的 因为我们每次都更新了G[v][w[i]-1]的值 }

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <string.h>
    using namespace std;
    const int maxn =100000+5;
    const int maxm=100+5;
    int up[maxn][maxm],down[maxn][maxm],w[maxn];
    vector<int>G[maxn];
    int n;
    void dfs(int cur, int per)
    {
          for(int i=0; i<=100; i++)up[cur][i]=n;
          memset(down[cur],0,sizeof(down[cur]));
          int siz =G[cur].size();
          int sum=1;
          for(int i=0; i<siz; i++)
          {
              int to=G[cur][i];
              if(to==per)continue;
              dfs(to,cur);
              if(w[cur]) sum+=down[to][w[cur]-1];
              else sum+=up[to][0];
              down[cur][0]+=up[to][0];
              for(int j=1; j<=100; j++)
                down[cur][j]+=down[to][j-1];
          }
          for(int i=0; i<siz; i++)
          {
              int to=G[cur][i];
              if(to==per)continue;
              up[cur][0]=min(up[cur][0],up[to][1]+down[cur][0]-up[to][0]);
              for(int j=1; j<100; j++)
                up[cur][j]=min(up[cur][j],up[to][j+1]+down[cur][j]-down[to][j-1]);
          }
          for(int i=0; i<=w[cur]; i++)up[cur][i]=min(up[cur][i],sum);
          for(int i=99; i>=0;i--)up[cur][i]=min(up[cur][i],up[cur][i+1]);
          down[cur][0]=min(down[cur][0],up[cur][0]);
          for(int i=1; i<=100; i++)
            down[cur][i]=min(down[cur][i],down[cur][i-1]);
    }
    int main()
    {
        while(scanf("%d",&n)==1)
            {
                  for(int i=1; i<=n; i++)
                    {
                           scanf("%d",&w[i]);
                           G[i].clear();
                    }
                    for(int i=1; i<n; i++)
                    {
                        int a,b;
                           scanf("%d%d",&a,&b);
                        G[a].push_back(b);
                        G[b].push_back(a);
                    }
                    dfs(1,0);
                    int ans=n;
                    for(int i=0; i<=100; i++)ans=min(ans,up[1][i]);
                    printf("%d
    ",ans);
            }
        return 0;
    }
    View Code
  • 相关阅读:
    希尔排序算法
    java面向对象的栈 队列 优先级队列的比较
    java不用任何已有方法完全自写的去重法
    java面向对象的冒泡排序,选择排序和插入排序的比较
    java面向对象的有序数组和无序数组的比较
    Truncated incorrect DOUBLE value:
    laradock 安装多php版本
    graph-composer, 面向 composer.json的依赖图可视化( PHP + Composer )
    php基础
    php通过curl调用webservice
  • 原文地址:https://www.cnblogs.com/Opaser/p/4783612.html
Copyright © 2020-2023  润新知