POJ 1947 Rebuilding Roads

来源:互联网 发布:看门狗mac版 编辑:程序博客网 时间:2024/06/07 02:28

Description

The cows havereconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number1..N) after the terrible earthquake last May. The cows didn't have time torebuild any extra roads, so now there is exactly one way to get from any givenbarn to any other barn. Thus, the farm transportation system can be representedas a tree. 

Farmer John wants to know how much damage another earthquake could do. He wantsto know the minimum number of roads whose destruction would isolate a subtreeof exactly P (1 <= P <= N) barns from the rest of the barns.

Input

* Line 1: Twointegers, N and P 

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

Output

A single linecontaining the integer that is the minimum number of roads that need to bedestroyed 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

题目大意:有n个点,现在要得到只含有p个点的子树。接着输入n-1条边将n个点相连。问要截断最少截断多少条边能得到只含有p个点的子树。

 

此题首先可以转化一下。每个点与之相连的点有num[i]个,则,得到含有p个点的子树需要截断的边为num[i]-2*(p-1)i为这p个点的编号。式子的得到是,得到的子树内部一共有p-1条边,而∑num[i]将每条边算了两次,即2*(p-1),要得到这个子树就需要截断这个子树外部的边,外部边的数目即,这p个点所含边数的总和减去2*内部的边的数目。而2*(p-1)对于问题来说是固定的。故现在问题就转化成了求p个点所含边数的总和的最小值。

 

dp[i][j]表示的是含有以i点为根节点的子树含有i点的连续j个点所含边数的总和的最小值。我们可以以任意一个点作为树的根节点进行遍历,每次只用计算其子节点即可。同时,一个问题是dp[i][1]要赋初值为num[i]dp[i]中必须含有点i

转移方程:dp[i][k] = min(dp[i][k],dp[i][j] + dp[re][k-j]);(rei的子节点)

 

#include <iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<vector>#define INF 0x03F3F3F3Fusing namespace std;int n ,p;vector<int> v[160];int num[160];int dp[160][160] ,flag[160];void solve(int x){    flag[x] = 1;    for(int i = 0;i < num[x];i++)    {        if(!flag[v[x][i]])        {            solve(v[x][i]);            for(int k = p;k>=1;k--)            {                for(int j = k;j>=1;j--)                {                    if(dp[x][k] > dp[x][j] + dp[v[x][i]][k-j])                    {                        dp[x][k] = dp[x][j] + dp[v[x][i]][k-j];                    }                }            }        }    }}int main(){    int u ,s ,m;    while(~scanf("%d%d",&n,&p))    {        memset(flag,0,sizeof(flag));        memset(dp,0x03F3F3F3F,sizeof(dp));        for(int i = 1;i<n;i++)        {            scanf("%d%d",&u,&s);            v[u].push_back(s);            v[s].push_back(u);        }        for(int i = 1;i<=n;i++)        {            num[i] = v[i].size();        }        for(int i = 1;i<=n;i++)        {            dp[i][1] = num[i];        }        solve(1);        m = INF;        for(int i = 1;i<=n;i++)        {            if(m > dp[i][p])            {                m = dp[i][p];            }        }        printf("%d\n",m-2*(p-1));        for(int i = 0;i<=n;i++)        {            v[i].clear();        }    }    return 0;}


 

0 0