1. 程式人生 > >poj1947 Rebuilding Roads(樹形揹包刪邊)

poj1947 Rebuilding Roads(樹形揹包刪邊)

The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The cows didn't have time to rebuild any extra roads, so now there is exactly one way to get from any given barn to any other barn. Thus, the farm transportation system can be represented as a tree.  Farmer John wants to know how much damage another earthquake could do. He wants to know the minimum number of roads whose destruction would isolate a subtree of exactly P (1 <= P <= N) barns from the rest of the barns.

Input

* Line 1: Two integers, N and P  * Lines 2..N: N-1 lines, each with two integers I and J. Node I is node J's parent in the tree of roads. 

Output

A single line containing the integer that is the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated. 

Sample Input

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

Sample Output

2

Hint

[A subtree with nodes (1, 2, 3, 6, 7, 8) will become isolated if roads 1-4 and 1-5 are destroyed.] 

題意:一顆含有n個結點的樹,求減去最少的邊使得該樹只含有p個結

’分析:典型的樹形揹包問題

,在樹上進行動態規劃,設dp[s][i]表示以s為根的子樹含有i個結點需要刪去的邊數,則得到轉移方程:

對於i的子樹k:

1.不加子樹k,dp[s][i] = dp[s][i] + 1 (不加子樹k,相當於刪去一條邊)

2.加子樹k,dp[s][i] = min(dp[s][j] + dp[k][i - j])  (1<= j <= i)   (以s為根的樹的結點數加上其子樹的結點數等於i)

最後答案就是在dp[i][m]中取小,要注意的一點是,如果i不是根,值還需要+1,因為要脫離原來的根,還要去掉一條邊

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define maxn 305
using namespace std;
struct point
{
    int v,next;
}edge[maxn];
int n,p,dp[maxn][maxn],cnt,vis[maxn],head[maxn];
void init()
{memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
cnt=0;
}
void addedge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u)
{
    for(int i=0;i<=p;i++)
    dp[u][i]=inf;
    dp[u][1]=0;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        dfs(v);
        for(int j=p;j>=1;j--)
        for(int k=0;k<j;k++)
        {
            if(k)
            dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]);
            else
            dp[u][j]=dp[u][j]+1;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&p);
    init();
    int x,y;
    for(int i=1;i<=n-1;i++)
    {scanf("%d%d",&x,&y);
    addedge(x,y);
    vis[y]=1;
    }

    int i;
    for(i=1;i<=n;i++)
    {
        if(!vis[i])
        break;
    }
    dfs(i);
    int ans=dp[i][p];
    for(int j=1;j<=n;j++)
    ans=min(ans,dp[j][p]+1);
    printf("%d\n",ans);

    return 0;
}