[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 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.]

Source

USACO 2002 February

题目链接

http://poj.org/problem?id=1947

题意

给你一棵节点为n的树。问至少砍几刀能够孤立出一棵节点为m的子树。

思路

找到根节点(入度为0)后dfs在每一个节点统计dp[i][j]

表示i及其的子树保留j个节点的最小代价;

int tmp=dp[x][ii]+1;//不要y节点;
tmp=min(tmp,dp[x][ii-j]+dp[y][j]);
dp[x][ii]=tmp;

y为x的儿子节点。

代码

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

int dp[155][155];
int ans;
int in[155];
vector<int> lin[155];
int n,aa,bb,p;
void dfs(int x)
{
    for(int i=2;i<=p;i++) dp[x][i]=99999999;
    if(lin[x].size()==0)
    dp[x][1]=0;
    for(int i=0;i<lin[x].size();i++)
    {
        int y=lin[x][i];
        dfs(y);
        for(int ii=p;ii>=1;ii--)
        {
            int tmp=dp[x][ii]+1;
            for(int j=1;j<ii;j++)
            tmp=min(tmp,dp[x][ii-j]+dp[y][j]);
            dp[x][ii]=tmp;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&p);
    {
        int ans=99999999;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&aa,&bb);
            lin[aa].push_back(bb);
            in[bb]++;
        }
        for(int i=1;i<=n;i++)
        if(!in[i])
        {
            dfs(i);
            ans=dp[i][p];
            break;
        }

        for(int i=1;i<=n;i++)
        ans=min(ans,dp[i][p]+1);
        printf("%d\n",ans);
    }

}
时间: 2024-10-15 14:20:45

[poj 1947] Rebuilding Roads 树形DP的相关文章

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 + 背包思想)

题目链接: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[

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. Th

树形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

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

POJ 1947 Rebuilding Roads (树形DP)

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

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