zoukankan      html  css  js  c++  java
  • poj1947

    开学A的第一道题还是1A,感觉还是很开心。

    设dp[i][k]为以i为子树的情况下变成一个子树节点为k的最少需要减掉的边数。那么对每个子树背包就可以了,注意的是刚开始需要将dp[a][1] = a != 1?num[a]-1:num[a];的意思是把a的与孩子连的边全部去掉时的情况,然后一步一步背包加边。

    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    const int maxa = 155;
    int edge[maxa][maxa];
    int num[maxa];
    int dp[maxa][maxa];     //包括i且只考虑i的子树的所有最小情况,
    int nt[maxa];           //以i为根的字数的节点数
    int ans;
        int n, p;
        int dp1[maxa];
    int dfs(int a, int fa){
        nt[a] = 1;
        for(int i = 0; i < num[a]; i++){
            int k = edge[a][i];
            if(k != fa){
                dfs(k, a);
            }
        }
        dp[a][1] = a != 1?num[a]-1:num[a];
    
        for(int i = 0; i < num[a]; i++){
            int k = edge[a][i];
            if(k != fa){
                for(int j = 1; j <= nt[a] + nt[k]; j ++){
                    dp1[j] = dp[a][j];
                }
                for(int j = 1; j <= nt[a]; j++){
                    for(int h = 1; h <= nt[k]; h++){
                        dp1[j+h] = min(dp1[j+h], dp[a][j] + dp[k][h]-1);
                    }
                }
                for(int j = 1; j <= nt[a] + nt[k]; j ++){
                    dp[a][j] = dp1[j];
                }
                nt[a] += nt[k];
            }
        }
        if(a == 1){
            ans = min(ans, dp[a][p]);
        }else ans = min(ans, dp[a][p] + 1);
    }
    int main(){
        while(scanf("%d%d", &n, &p)!=EOF){
            int a, b;
            memset(num, 0, sizeof(num));
            for(int i  = 1; i < n; i++){
                scanf("%d%d", &a, &b);
                edge[a][num[a]++] = b;
                edge[b][num[b]++] = a;
            }
            for(int i = 1; i <= n; i++){
                for(int k =  1; k <= n; k++){
                    dp[i][k] = maxa;
                }
            }
            ans = maxa;
            dfs(1, 0);
            printf("%d
    ", ans);/*
            for(int  i = 1; i <= n; i++){
                printf("%d %d * ", nt[i], i);
                for(int k = 1; k <= n; k++){
                    printf("%d ", dp[i][k]);
                }printf("
    ");
            }*/
        }
    }
    /*
    11 6
    1 2
    1 3
    1 4
    1 5
    2 6
    2 7
    2 8
    4 9
    4 10
    4 11
    11 1
    1 2
    1 3
    1 4
    1 5
    2 6
    2 7
    2 8
    4 9
    4 10
    4 11
    */
    View Code
  • 相关阅读:
    小小杨的影视空间
    关于励志的事情
    关于2020年的总结
    关于心情不好的时候
    关于我的2020年
    单链表基本操作的实现
    原型模式
    android—安卓系统文件目录结构
    android——apk安装文件的组成结构
    android——项目的组成结构
  • 原文地址:https://www.cnblogs.com/icodefive/p/4309308.html
Copyright © 2011-2022 走看看