poj 1947

/*
dp【s】【i】代表以s为根的剩余的为i个子节点的所需要删除最小的边数
*/

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define N  155
#define inf 0x3f3f3f3f

int dp[N][N];
int b[N];
int a[N];
int root;
int vis[N];
int son[N];
int n,p;
//思路就是一层一层的搜下去
void dfs(int s){

    dp[s][1]=0;//只剩余一个点的话 不需要删除边

    int k=son[s];

    while(k){
        dfs(k);
        for(int i=p;i>0;i--){
            int tmp = dp[s][i]+1;//如果删除了i节点  那么只需要+1
            for (int j = 1; j < i; ++ j)
            {
                if (dp[k][i - j] + dp[s][j] < tmp)//如果不删除的话,那么要判断k的子树是否存在删除变更少的边的可能
                {
                    tmp = dp[k][i - j] + dp[s][j];
                }
            }
            dp[s][i]=tmp;
        }
        k=b[k];//继续从他的兄弟
    }
}

int main(){
    while(scanf("%d%d",&n,&p)==2){
        memset(dp,inf,sizeof(dp));
        memset(son,0,sizeof(son));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<n;i++){
            int  s, t;
            scanf("%d%d",&s,&t);
            b[t]=son[s];//他的兄弟是当前s的儿子
            vis[t]=1;
            son[s]=t;//把它设为当前的儿子
        }
        for(int i=1;i<=n;i++){
            if(!vis[i]){
                root = i;
                break;
            }
        }
        //printf("root = %d\n",root);
        dfs(root);

        int ans  = dp[root][p];

        for(int i=1;i<=n;i++){
            if(ans>dp[i][p]+1){
                ans=dp[i][p]+1;
            }
        }

        printf("%d\n",ans);
    }
}
时间: 2024-11-25 15:01:14

poj 1947的相关文章

poj 1947(树形dp)

题意:一棵树上问你最少切掉几条边使得能分割出一个结点数正好为k的子树. 思路:dp[i][j]表示以i为根切掉j个结点最少要几条边. dp[v][j] = min(dp[v][j], dp[v][j-k] + dp[x][k]); 代码如下: 1 dp[v][j] = min(dp[v][j], dp[v][j-k] + dp[x][k]); 2 } 3 } 4 } 5 } 6 } 7 return vex[v]; 8 } 9 10 int main() 11 { 12 // freopen("

POJ 1947 树形DP入门题

给出N个点,N-1个关系,建出树形图,问最少减去几个边能得到节点数为P的树.典型树形DP题 dp[cur][j] :记录cur结点,要得到一棵j个节点的子树去掉的最少边数 转移方程用的背包的思想 对当前树的每一个子树进行计算 砍掉此子树:   dp[cur][j]=dp[cur][j]+1; 不砍掉:           for (l=0;l<=j;l++)  dp[cur][j]=Min(dp[cur][j],dp[cur][l]+dp[next][j-l]); 枚举从该树中留l个节点其他由新

[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: 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[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

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 (树形DP+背包)

题目链接: http://poj.org/problem?id=1947 题目大意:树中各点都由一条边连接.问要弄出个含有m个点的(子)树,至少需要截去多少条边. 解题思路: 设dp[i][j]为i总根(注意是当前点为总根,不再考虑其父亲,这题是要在原来的树里面切出一个树),留下j个点截去的最少的边. 首先dp[i][1]=子结点数量,即只留下根,要把所有与子节点的边给截掉. 对于dp[i][2~m]:如果取子结点,则dp[i][j]=min(dp[i][j],dp[i][j-k]+dp[t][

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

poj 1947 经典树形dp

经典树形dp:问在一棵树上最少删除多少条边可以分离出一个节点数为p的子树. 定义状态: dp[i][j]表示从i为根的子树上分离出一个节点数为j的子树的代价(最少需要删除的边数). 考虑i节点的每个儿子ii,ii可以选或者不选(切断),然后就转化成了背包问题. dp[u][j] = min( dp[u][j], dp[u][j - k] + dp[v][k] ); 1 #include <iostream> 2 #include <cstring> 3 #include <c

POJ 1947 Rebuilding Roads

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