poj 1947

来源:互联网 发布:基础数据 英文 编辑:程序博客网 时间:2024/04/29 20:35


/*dp【s】【i】代表以s为根的剩余的为i个子节点的所需要删除最小的边数*/#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define N  155#define inf 0x3f3f3f3fint 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);    }}


0 0