poj 1947 Rebuilding Roads 【树形DP】 【求至少删去树中 多少条边 使得树中节点数为P】

Rebuilding Roads

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 10066   Accepted: 4595

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

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个点和N-1条边构成的树,问你最少删去几条边使得新树中节点数为P。

思路:用dp[i][j]表示以i节点为根的树 中选中j个节点 最少需要删去的边数。

我们利用树形dp的思想,考虑u节点的子节点v。

一:直接去掉<u,v>边即去掉以v为根的子树,显然有dp[u][j] + 1;

二:保留边<u,v>,那么有dp[u][j-k] + dp[v][k],(1<= k <= j)。对于该情况我们要求出(1<=k<=j)范围的最小值再和第一种情况比较。

这样得到状态转移方程

dp[u][v] = min ( min(dp[u][j-k]+dp[v][k] ) , dp[u][v] + 1).

AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define MAXN 200
#define INF 0x3f3f
using namespace std;
vector<int> G[MAXN];
int dp[MAXN][MAXN];//dp[i][j]存储以i节点为根的树 选j个点 最少删的边数
int pre[MAXN];
int N, P;
void init()
{
    for(int i = 1; i <= N; i++)
        G[i].clear(), pre[i] = i;
}
void getMap()
{
    int a, b;
    for(int i = 1; i < N; i++)
    {
        scanf("%d%d", &a, &b);
        G[a].push_back(b);
        pre[b] = a;
    }
}
int num[MAXN];
void DFS(int u)
{
    dp[u][1] = 0;//初始 自己不删边
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        DFS(v);
        for(int j = P; j >= 0; j--)
        {
            int t = dp[u][j] + 1;//直接删掉 与 子节点v 相连的边
            for(int k = 0; k <= j; k++)
                t = min(t, dp[u][j-k] + dp[v][k]);
            dp[u][j] = t;
        }
    }
}
void solve()
{
    int root;
    for(int i = 1; i <= N; i++)
    {
        if(pre[i] == i)
        {
            root = i;
            break;
        }
    }
    memset(dp, INF, sizeof(dp));
    DFS(root);
    int ans = INF;
    for(int i = 1; i <= N; i++)
    {
        if(i == root)//删边后 原根节点 依旧在
            ans = min(ans, dp[i][P]);
        else//删边后 原根节点已经没了 加上去掉根的一条边
            ans = min(ans, dp[i][P] + 1);
    }
    printf("%d\n", ans);
}
int main()
{
    while(scanf("%d%d", &N, &P) != EOF)
    {
        init();
        getMap();
        solve();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-21 23:08:46

poj 1947 Rebuilding Roads 【树形DP】 【求至少删去树中 多少条边 使得树中节点数为P】的相关文章

POJ 1947 Rebuilding Roads (树形dp 经典题)

Rebuilding Roads Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 9499   Accepted: 4317 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

[POJ 1947]Rebuilding Roads (树形dp)

题目链接:http://poj.org/problem?id=1947 题目大意:给你一棵树,树上N个节点.问最少拆掉多少条边使得存在一个联通块,有P个节点. 树形dp,设计状态:dp[u][i]代表以u为根节点的剩下i个节点最少需要拆掉多少条边. 状态转移:dp[u][i+j] = min(dp[u][i+j],dp[u][i]+dp[v][j]-1); 其中v是u的儿子节点. 相当于在树上跑01背包,即每个儿子节点去掉剩下j个的但是要连上u-v边,或者不去掉剩下j个的. 代码: 1 impo

[poj 1947] Rebuilding Roads 树形DP

Rebuilding Roads Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 10653 Accepted: 4884 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 co

POJ 1947 Rebuilding Roads (树dp + 背包思想)

题目链接:http://poj.org/problem?id=1947 一共有n个节点,要求减去最少的边,行号剩下p个节点.问你去掉的最少边数. dp[u][j]表示u为子树根,且得到j个节点最少减去的边数. 考虑两种情况,去掉孩子节点v与去不掉. (1)去掉孩子节点:dp[u][j] = dp[u][j] + 1 (2)不去掉孩子节点:dp[u][j] = min(dp[u][j - k] + dp[v][k]) 综上就是dp[u][j] = min(dp[u][j] + 1, min(dp[

树形DP [POJ 1947] Rebuilding Roads

Rebuilding Roads Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 9249   Accepted: 4198 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

POJ 1947 Rebuilding Roads (树形DP)

题意:给一棵树,在树中删除一些边,使得有一个连通块刚好为p个节点,问最少需要删除多少条边? 思路: 因为任一条边都可能需要被删除,独立出来的具有p个节点的连通块可能在任意一处地方.先从根开始DFS,然后进行树DP,dp[t][i]表示在以t为根的子树中删除i个点需要删除多少条边.dp[t][n-p]有可能是答案了,但是这种仅考虑到从树上脱落掉部分子树,那么留下的连通块通常是与1号点(树根)相连的,那如果所需要的连通块是在某棵子树中呢?将所有可能的子树取出来,若该子树节点数>=p,那么就可以在该子

POJ 1947 Rebuilding Roads

题目大意: 根据两个点建立一条有向边,最后可形成的是一棵树,希望通过切除一些边,使一棵含有p个节点的子树被独立出来,希望切除的边数最少,输出这个边数 这个是第一次自己完完整整做出来的树形Dp题目,没有参考别人的DP思路,虽然自己很快想好了,但是总是无法合适的进行组织,做了很久,但自己做出来的 总是会比取理解别人代码来的效果好很多 用dp[u][j] 记录u号节点这棵子树中含有j个点需要砍去的最少的边数 两次dfs , 第一次dfs查出对应节点的下方子树中一共有多少个节点,顺便记录一个节点在当前延

POJ 1947 Rebuilding Roads(树形DP)

题目链接 题意 : 给你一棵树,问你至少断掉几条边能够得到有p个点的子树. 思路 : dp[i][j]代表的是以i为根的子树有j个节点.dp[u][i] = dp[u][j]+dp[son][i-j]-1,son是u的儿子节点.初始是将所有的儿子都断开,然后-1代表的是这个儿子我需要了,不断了. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream>

DP Intro - poj 1947 Rebuilding Roads

算法: dp[i][j]表示以i为根的子树要变成有j个节点的状态需要减掉的边数. 考虑状态转移的时候不考虑i的父亲节点,就当不存在.最后统计最少减去边数的 时候+1. 考虑一个节点时,有两种选择,要么剪掉跟子节点相连的边,则dp[i][j] = dp[i][j]+1; 要么不剪掉,则d[i][j] = max(dp[i][j], dp[i][k]+dp[son][j-k]); [cpp] view plain copy print? #include<cstdio> #include<c