http://poj.org/problem?id=1947

给你一棵n个节点的树 问你保存p个节点的子树最少需要切断多少条边

我用邻接表保存树

ans[i][j] 代表了包含i在内的它所要子节点和兄弟子树在内 保存j个点需要最少切断多少边

代码及其注释:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<stack>
#include<algorithm>
#define LL long long

using namespace std;

const int N=155;
const int M=1000001;
struct node
{
    struct tt *next;
}mem[N];
struct tt
{
    int j;
    struct tt *next;
};
int ans[N][N];
void build(int i,int j)
{
    struct tt *t=new tt;
    t->j=j;
    t->next=mem[i].next;
    mem[i].next=t;
}
void Dele(int n)
{
    struct tt *t;
    for(int i=1;i<=n;++i)
    {
        while(mem[i].next!=NULL)
        {
            t=mem[i].next;
            mem[i].next=t->next;
            delete t;
        }
    }
}
int dp(struct tt *t,int k)
{
    if(t==NULL)//如果为空了
    {
        if(k==0)//保存0个的话反回0
        return 0;
        else
        return M;//否则反回最大
    }
    if(ans[t->j][k]!=-1)
    return ans[t->j][k];
    if(k==0)//保存0 个的话 需要切断所以兄弟节点与负节点的连线
    {
        ans[t->j][k]=1+dp(t->next,k);
        return ans[t->j][k];
    }
    ans[t->j][k]=1+dp(t->next,k);//此节点子树与父节点切断
    for(int i=1;i<=k;++i)
    {
        //递归找最优
        ans[t->j][k]=min(ans[t->j][k],dp(mem[t->j].next,i-1)+dp(t->next,k-i));
    }
    return ans[t->j][k];
}
int main()
{
    int n,k;
    while(scanf("%d %d",&n,&k)!=EOF)
    {
        for(int i=1;i<n;++i)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            build(x,y);
        }
        if(n==1)
        {
            printf("0\n");
            continue;
        }
        int MIN=M;
        memset(ans,-1,sizeof(ans));
        MIN=min(MIN,dp(mem[1].next,k-1));
        for(int i=2;i<=n;++i)
        {
            MIN=min(MIN,1+dp(mem[i].next,k-1));//不一定值保存 1
        }

        printf("%d\n",MIN);
        Dele(n);
    }
}

  

 

 

posted on 2012-07-23 10:20  夜->  阅读(159)  评论(0编辑  收藏  举报