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

poj 1947

时间:2015-05-18 16:49:03      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:


/*
dp【s】【i】代表以s为根的剩余的为i个子节点的所需要删除最小的边数
*/

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define N  155
#define inf 0x3f3f3f3f

int dp[N][N];
int b[N];
int a[N];
int root;
int vis[N];
int son[N];
int n,p;
//思路就是一层一层的搜下去
void dfs(int s){

    dp[s][1]=0;//只剩余一个点的话 不需要删除边

    int k=son[s];

    while(k){
        dfs(k);
        for(int i=p;i>0;i--){
            int tmp = dp[s][i]+1;//如果删除了i节点  那么只需要+1
            for (int j = 1; j < i; ++ j)
            {
                if (dp[k][i - j] + dp[s][j] < tmp)//如果不删除的话,那么要判断k的子树是否存在删除变更少的边的可能
                {
                    tmp = dp[k][i - j] + dp[s][j];
                }
            }
            dp[s][i]=tmp;
        }
        k=b[k];//继续从他的兄弟
    }
}

int main(){
    while(scanf("%d%d",&n,&p)==2){
        memset(dp,inf,sizeof(dp));
        memset(son,0,sizeof(son));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<n;i++){
            int  s, t;
            scanf("%d%d",&s,&t);
            b[t]=son[s];//他的兄弟是当前s的儿子
            vis[t]=1;
            son[s]=t;//把它设为当前的儿子
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                root = i;
                break;
            }
        }
        //printf("root = %d\n",root);
        dfs(root);

        int ans  = dp[root][p];

        for(int i=1;i<=n;i++){
            if(ans>dp[i][p]+1){
                ans=dp[i][p]+1;
            }
        }

        printf("%d\n",ans);
    }
}


poj 1947

标签:

原文地址:http://blog.csdn.net/u013076044/article/details/45822795

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