树形DP集锦2

来源:互联网 发布:归并排序 c语言 编辑:程序博客网 时间:2024/06/16 09:52

一共有n(<=200)个国家, 你想要至少收买m(<=m)个国家,其中收买国家i的代价是w[ i ]。但是有些国家有拥属关系,如果A拥属B国,就是买通了A也意味着买通了B,而且这些关系是传递的。求最少需要付出的代价。(poj)

读入有点意思。

const  int maxn = 208  ;int  n , m ;vector<int> g[maxn] ;int  w[maxn] ;int  dp[maxn][maxn] , son[maxn] ;void  dfs(int u){      son[u] = 1 ;      dp[u][0] = 0 ;      for(int i =  0 ;  i < g[u].size() ; i++){           int v = g[u][i] ;           dfs(v) ;           for(int k = n ; k >= 0 ; k--){               for(int j = 0 ; j <= k ; j++)                   dp[u][k] = min(dp[u][k] , dp[u][k-j] + dp[v][j]) ;           }           son[u] += son[v] ;      }      dp[u][son[u]] = min(dp[u][son[u]] , w[u]) ;}int  in[maxn]  ;char str[1008] ;map<string , int> h ;int  main(){     int  i , id , u , v ;     while(gets(str)){          if(str[0] == '#') break ;          sscanf(str , "%d%d" ,&n ,&m) ;          for(i = 0 ; i <= n ; i++) g[i].clear()  ;          h.clear() ;          id = 0 ;          memset(in , 0 , sizeof(in)) ;          memset(son , 0 , sizeof(son)) ;          memset(dp , 63 , sizeof(dp)) ; //最大值inf          for(i = 1 ; i <= n ; i++){               scanf("%s" ,str) ;               if(h.find(str) == h.end()) h[str] = ++id ;               u = h[str] ;               scanf("%d" ,&w[u]) ;               gets(str) ;               stringstream s(str) ;               string name ;               while(s>>name){                    if(h.find(name) == h.end())  h[name] = ++id ;                    v = h[name] ;                    g[u].push_back(v) ;                    in[v]++ ;               }          }          for(i = 1 ; i <= n ; i++){               if(in[i]==0) g[0].push_back(i) ;          }          dfs(0) ;          int s = dp[0][m] ;          for(i = m ; i <= n ; i++)  s = min(s , dp[0][i]) ;          printf("%d\n" , s) ;     }     return 0 ;}

给出一个大小为n的树,几每个节点的权值。问这棵树中大小m的子树最大权值。(zoj)

const int  maxn = 108 ;vector<int> g[maxn] ;int   dp[maxn][maxn] ;int   n , m ;bool  vis[maxn] ;void  dfs(int u){      vis[u] = 1 ;      for(int i = 0 ; i < g[u].size() ; i++){           int v = g[u][i] ;           if(vis[v]) continue ;           dfs(v) ;           for(int j = m ; j > 1 ; j--){               for(int k = 1 ; k < j ; k++)                   dp[u][j] = max(dp[u][j] , dp[u][j-k] + dp[v][k]) ;           }      }}int  main(){     int i , u , v  ;     while(scanf("%d%d" ,&n ,&m) != EOF){          for(i = 0 ; i <= n ; i++) g[i].clear() ;          memset(vis , 0 , sizeof(vis)) ;          memset(dp , 0 , sizeof(dp)) ;          for(i = 0 ; i < n ; i++) scanf("%d" ,&dp[i][1]) ;          for(i = 1 ; i < n ; i++){               scanf("%d%d" ,&u ,&v) ;               g[u].push_back(v) ;               g[v].push_back(u) ;          }          int s = 0 ;          dfs(0) ;          for(i = 0 ; i < n ; i++) s = max(s , dp[i][m]) ;          printf("%d\n" ,s) ;     }     return 0 ;}

给出一棵树,问最少切断几条边可以得到有p个结点的子树。(poj)

dp[i][j]表示以第i个节点为根的子树保留j个节点最少需要去掉几条边
const int  maxn = 158 ;vector<int> g[maxn] ;int  dp[maxn][maxn] ;int  m  ;void  dfs(int u , int father){      dp[u][1] = 0 ;      for(int i = 0 ; i < g[u].size() ; i++){           int v = g[u][i] ;           if(v == father) continue  ;           dfs(v , u) ;           for(int j = m ; j >= 1 ; j--){               dp[u][j] = dp[u][j] + 1 ;               for(int k = 1 ; k < j ; k++)                   dp[u][j] = min(dp[u][j] , dp[u][j-k] + dp[v][k]) ;           }      }}int  main(){     int i , n , u , v  , s ;     while(cin>>n>>m){          for(i = 1 ; i <= n ; i++) g[i].clear() ;          for(i = 1 ; i < n ; i++){               scanf("%d%d" ,&u ,&v) ;               g[u].push_back(v) ;               g[v].push_back(u) ;          }          memset(dp , 63 , sizeof(dp)) ;          dfs(1, -1) ;          s = dp[1][m] ;          for(i = 2 ; i <= n ; i++) s = min(s , dp[i][m] + 1) ;          printf("%d\n" ,s) ;     }     return 0 ;}

树,给每个结点的value 和 weight 。求容量为m的背包,能获得的最大value。选择了父结点才能选择子结点。m = 0时 ,输出0 。

const  int  maxn = 108 ;vector<int> g[maxn] ;int    w[maxn] , val[maxn] ;int    dp[maxn][maxn] ;int    m ;void   dfs(int u , int father){       for(int i = w[u] ; i <= m ; i++) dp[u][i] = val[u] ;       for(int e = 0 ; e < g[u].size() ; e++){           int v = g[u][e] ;           if(v == father)  continue  ;           dfs(v , u)  ;           for(int i = m ; i >= w[u] ; i--){               for(int j = 1 ; i-j >= w[u] ; j ++) //必须选父亲                   dp[u][i] = max( dp[u][i] , dp[u][i-j]+dp[v][j] ) ;           }       }}int   main(){      int n  , i , u , v  ;      while(cin>>n>>m){           if(n==-1 && m==-1)  break ;           for(i = 1 ; i <= n ; i++) g[i].clear() ;           for(i = 1 ; i <= n ; i++){                scanf("%d%d" ,&w[i] , &val[i]) ;                w[i] = (w[i]+19)/20  ;           }           for(i = 1 ; i < n ; i++){                scanf("%d%d" ,&u ,&v) ;                g[u].push_back(v) ;                g[v].push_back(u) ;           }           if(m == 0){puts("0") ; continue  ; }           memset(dp , 0 , sizeof(dp)) ;           dfs(1 , -1) ;           printf("%d\n" , dp[1][m]) ;      }      return 0 ;}





0 0
原创粉丝点击