码迷,mamicode.com
首页 > 其他好文 > 详细

hdu5290树形dp

时间:2015-09-05 22:15:21      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:

题意 给了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\n",ans);
        }
    return 0;
}
View Code

 

hdu5290树形dp

标签:

原文地址:http://www.cnblogs.com/Opaser/p/4783612.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!