zoukankan      html  css  js  c++  java
  • 洛谷P1272 重建道路(树形DP+分组背包)

    题目描述

    一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。John想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目。

    输入格式

    第1行:2个整数,N和P

    第2..N行:每行2个整数I和J,表示节点I是节点J的父节点。

    输出格式

    单独一行,包含一旦被破坏将分离出恰含P个节点的子树的道路的最小数目。

    输入输出样例

    输入 #1
    11 6
    1 2
    1 3
    1 4
    1 5
    2 6
    2 7
    2 8
    4 9
    4 10
    4 11
    
    输出 #1
    2
    不是很明白为啥题解都热衷于建无向图...这明明是一棵有根树啊...直接找到根节点dfs就可以了。
    dp[i][j]:i这个节点得到j个节点的子树(包括自己)且与i节点的父亲节点相连所需要删除的最少边数 转移方程在熟悉的套路上稍作改动: dp[x][j]=min(dp[x][j],dp[x][j-k]+dp[y][k]-1);因为在初始化的时候都是与儿子不相连的,去掉的边也累计进去了,但转移的时候要连起来因此要把这一条边补上。
    还有就是最后答案是max(dp[i][p])而非dp[root][p]。
    #include <bits/stdc++.h>
    #define N 310
    using namespace std;
    int n,p,head[N],ver[N],Next[N],tot=0,size[N]={0};
    int dp[N][N]={0};//dp[i][j]:i这个节点得到j个节点的子树(包括自己)且与i节点的父亲节点相连所需要删除的最少边数 
    bool vis[N]={0};
    void add(int x,int y)
    {
        ver[++tot]=y,Next[tot]=head[x],head[x]=tot;    
     } 
    void dfs(int x)
     {
         //初始化
         dp[x][1]=size[x];//与所有儿子断绝关系 
         int i,j,k;
         for(i=head[x];i;i=Next[i])
         {
             int y=ver[i];
             dfs(y);
            for(j=p;j>=1;j--)//背包容量 其实直接从p开始就好 没必要从前xx棵子树的节点总数开始 从大到小枚举是因为压缩掉了 前xx棵子树 这一维度 
            {
                for(k=1;k<j;k++)
                {
                    dp[x][j]=min(dp[x][j],dp[x][j-k]+dp[y][k]-1);
                }
            }
        }
     }
    int main()
    {
        cin>>n>>p;
        int i;
        memset(dp,0x3f3f3f3f,sizeof(dp));//注意初始化 
        memset(size,0,sizeof(size));
        memset(vis,0,sizeof(vis));
        for(i=1;i<=n-1;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
            size[x]++;//儿子个数 
            vis[y]=1;//是儿子的就标记上 
        }
        int root;
        for(i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                root=i;
                break;
            }
            dp[i][1]=size[i];
        }
        dfs(root);
        int ans=dp[root][p]; 
        for(i=1;i<=n;i++)
        {
            if(dp[i][p]<ans)ans=dp[i][p]+1;
        }
        cout<<ans;//有问题 
    } 
  • 相关阅读:
    [J2ME Q&A]MMAPI的Cannot parse this type of AMR异常之讨论
    FM91.5的EasyMorning节目爱听吗?
    [EntLibFAQ]“不允许所请求的注册表访问权”的解释[0508Update]
    亮出你的组合竞争力的王牌
    隔离,隔离,再隔离!
    zuma三阶段论和技术道路[一]
    分享下我们部门内部知识点培训教程[SIP/J2ME/Setup/LoadRunner/Domino][0706Up]
    [Remoting FAQ]Loading a Remoting Host On IIS得到BadImageFormatException
    通过讲课来建立自己的知识系统
    j2medev“用户界面和多媒体”版面问题整理[0407更新]
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12571389.html
Copyright © 2011-2022 走看看