zoukankan      html  css  js  c++  java
  • POJ 1947 Rebuilding Roads (树dp + 背包思想)

    题目链接:http://poj.org/problem?id=1947

    一共有n个节点,要求减去最少的边,行号剩下p个节点。问你去掉的最少边数。

    dp[u][j]表示u为子树根,且得到j个节点最少减去的边数。

    考虑两种情况,去掉孩子节点v与去不掉。

    (1)去掉孩子节点:dp[u][j] = dp[u][j] + 1

    (2)不去掉孩子节点:dp[u][j] = min(dp[u][j - k] + dp[v][k])

    综上就是dp[u][j] = min(dp[u][j] + 1, min(dp[u][j - k] + dp[v][k]))

     1 //#pragma comment(linker, "/STACK:102400000, 102400000")
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstdlib>
     5 #include <cstring>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <ctime>
    10 #include <list>
    11 #include <set>
    12 #include <map>
    13 using namespace std;
    14 typedef long long LL;
    15 typedef pair <int, int> P;
    16 const int N = 155;
    17 int dp[N][N], n, p, inf = 1e8;
    18 vector <int> edge[N];
    19 //dp[i][j]表示i为子树根,且得到j个节点最少减去的边数。不考虑父节点
    20 
    21 void dfs(int u, int par) {
    22     for(int i = 2; i <= p; ++i) {
    23         dp[u][i] = inf;
    24     }
    25     dp[u][1] = 0; //考虑到叶子节点,而非叶子节点在下面的for中会增加
    26     for(int i = 0; i < edge[u].size(); ++i) {
    27         int v = edge[u][i];
    28         if(v == par)
    29             continue;
    30         dfs(v, u);
    31         for(int j = p; j >= 1; --j) { 
    32         //有点背包的思想,正序的话dp[u][j]可能由dp[v][k]转移而来,在下面会被重复转移。倒序的话保证转移一次。
    33             int temp = dp[u][j] + 1; //去掉v子树
    34             for(int k = 1; k < j; ++k) {
    35                 temp = min(dp[u][j - k] + dp[v][k], temp);
    36             }
    37             dp[u][j] = temp; //最优 跟最短路思想类似
    38         }
    39     }
    40 }
    41 
    42 int main()
    43 {
    44     int u, v;
    45     while(~scanf("%d %d", &n, &p)) {
    46         for(int i = 1; i <= n; ++i) {
    47             edge[i].clear();
    48         }
    49         for(int i = 1; i < n; ++i) {
    50             scanf("%d %d", &u, &v);
    51             edge[u].push_back(v);
    52             edge[v].push_back(u);
    53         }
    54         dfs(1, -1);
    55         int res = dp[1][p]; //根节点没有父亲 不需要+1
    56         for(int i = 2; i <= n; ++i) {
    57             res = min(dp[i][p] + 1, res); //其他节点有父节点 去除的话所以+1
    58         }
    59         printf("%d
    ", res);
    60     }
    61     return 0;
    62 }

    这题感觉好难想,人笨没办法

  • 相关阅读:
    oracle11g 新特性
    RMAN 报:ORA-19504 ORA-27038
    ORACLE-用户常用数据字典的查询使用方法
    oracle
    收缩 表空间
    oracle 配置 oem
    索引大小及占表的空间
    Oracle 11g Windows 迁移至 Linux
    Python:列表生成式
    Python:字符串处理函数
  • 原文地址:https://www.cnblogs.com/Recoder/p/5839967.html
Copyright © 2011-2022 走看看