程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ1947:Rebuilding Roads(樹形DP)

POJ1947:Rebuilding Roads(樹形DP)

編輯:C++入門知識

Description

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

2Hint

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

題意:給出n,p,一共有n個節點,要求最少減去最少的邊是多少,剩下p個節點
思路:典型的樹形DP,
dp[s][i]:記錄s結點,要得到一棵j個節點的子樹去掉的最少邊數
 考慮其兒子k
 1)如果不去掉k子樹,則
 dp[s][i] = min(dp[s][j]+dp[k][i-j])  0 <= j <= i

 2)如果去掉k子樹,則
 dp[s][i] =  dp[s][i]+1
 總的為
 dp[s][i] = min (min(dp[s][j]+dp[k][i-j]) ,  dp[s][i]+1 )

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

int n,p,root;
int dp[155][155];
int father[155],son[155],brother[155];

void dfs(int root)
{
    int i,j,k,tem;
    for(i = 0; i<=p; i++)
        dp[root][i] = 10000000;
    dp[root][1] = 0;
    k = son[root];
    while(k)
    {
        dfs(k);
        for(i = p; i>=1; i--)
        {
            tem = dp[root][i]+1;
            for(j = 1; j<i; j++)
                tem = min(tem,dp[k][i-j]+dp[root][j]);
            dp[root][i] = tem;
        }
        k = brother[k];
    }
}

int solve()
{
    int ans,i;
    dfs(root);
    ans = dp[root][p];
    for(i = 1; i<=n; i++)//除了根節點,其他節點要想成為獨立的跟,必先與父節點斷絕關系,所以要先加1
        ans = min(ans,dp[i][p]+1);
    return ans;
}

int main()
{
    int i,x,y;
    while(~scanf("%d%d",&n,&p))
    {
        memset(father,0,sizeof(father));
        memset(son,0,sizeof(son));
        for(i = 1; i<n; i++)
        {
            scanf("%d%d",&x,&y);
            father[y] = 1;//記錄該點有父親節點
            brother[y] = son[x];//記錄兄弟節點
            son[x] = y;//記錄子節點
        }
        for(i = 1; i<=n; i++)
        {
            if(!father[i])//找到根節點
            {
                root = i;
                break;
            }
        }
        printf("%d\n",solve());
    }

    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved