• POJ


    传送门

    有一颗N个结点的树,求需要割掉至少多少条边才能得到一颗恰好有P个结点的树

    没做出来,看了大神的解法才懂怎么做的orz

    用了dp[root][i]表示用一颗以root为根的树,需要割点多少条边才能得到以root为根的恰好有i个结点的树。这样以来就有子问题,可以进行dp。

    最后的答案里,由于在这个过程中,我们默认了root为根,但如果实际它有父亲,得到的dp[root][P]应该再加一

    状态转移:dp[root][i] = min(dp[root][i - k] + dp[child][k] - 1,dp[root][i]);

    每次在dp时,边界的话是,dp[root][1] = G[root].size();(儿子的数量),此时我们对每个结点的值,已经将它与儿子的边割掉。对于root的第一颗子树,假设子树上有cnt个结点,将子树连接上来,那么这时我们处理的是一颗有cnt+1个结点的树,会得到dp[root][i]({i} ⊆[1,cnt + 1],当i>cnt+1时,值取INF。在接下来的子树中,就可以利用上前面的子树与根结点构成的树的值。

    实际的操作过程中,是先得到一个根结点root,然后将它的一颗颗子树连接上来,并更新值,所以已经得到的树中取i-k个结点的值加上新子树取k个结点的值,最后才应该再减一,表示复原原本两个root与child间的边。

     1 #include <vector>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define INF 0x3f3f3f3f
     6 using namespace std;
     7 
     8 const int maxn = 155;
     9 vector<int> G[maxn];
    10 int deg[maxn], sum[maxn];
    11 int dp[maxn][maxn];
    12 int N, M;
    13 
    14 
    15 void dfs(int node) {
    16     for (int i = 0; i < G[node].size(); i++) {
    17         int u = G[node][i];
    18         dfs(u);
    19         sum[node] += sum[u];
    20         for (int j = sum[node]; j > 0; j--) {
    21             for (int s = 1; s < j; s++) {
    22                 dp[node][j] = min(dp[node][j], dp[node][j - s] + dp[u][s] - 1);
    23             }
    24         }
    25     }
    26 }
    27 
    28 int main(int argc, const char * argv[]) {
    29     scanf("%d%d", &N, &M);
    30     for (int i = 0; i <= N; i++) G[i].clear();
    31     memset(dp, INF, sizeof(dp));
    32     for (int i = 1; i < N; i++) {
    33         int u, v;
    34         scanf("%d%d", &u, &v);
    35         G[u].push_back(v);
    36         ++deg[u];
    37     }
    38     for (int i = 1; i <= N; i++) {
    39         dp[i][1] = deg[i];
    40         sum[i] = 1;
    41     }
    42     dfs(1);
    43     int ans = dp[1][M];
    44     for (int i = 2; i <= N; i++) {
    45         ans = min(ans, dp[i][M] + 1);
    46     }
    47     printf("%d
    ", ans);
    48     return 0;
    49 }
  • 相关阅读:
    第二次结对作业
    第一次结对作业
    第二次个人编程
    第一次编程作业
    第一篇随笔
    个人总结
    第三次个人作业
    第二次结对作业
    第一次结对作业
    第二次编程
  • 原文地址:https://www.cnblogs.com/xFANx/p/7495552.html
Copyright © 2020-2023  润新知