poj 1947 Rebuilding Roads

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);

    }

}

  

 

 

你可能感兴趣的:(Build)