zoukankan      html  css  js  c++  java
  • [洛谷P1272] 重建道路

    类型:树形背包

    传送门:>Here<

    题意:给出一棵树,要求断开$k$条边来分离出一棵有$P$个节点的子树。求最小的$k$

    解题思路

    和上一题类型相同,但不那么好做了——分离出的一棵子树肯定是在一起的,不能是散的,因此这给dp带来了难度

    $dp[u][i][j]$表示节点$u$的子树内,在前$i$棵子树内分离出有$j$个节点的子树,最少断的边。特别需要注意的是,这里的有$j$个节点的子树必须包含节点$u$

    想到这个定义以后就不难了,有方程$$dp[u][i][j]=Min{dp[u][i-1][j-k]+dp[v][numson[v]][k]-2}$$相当于在前$i-1$棵子树中分离出包含$u$的大小为$j-k$的子树,并且在当前子树分离出$k$的。注意为什么要$-2$,因为这两个部分为了确保独立性,前者肯定会断掉边$(u,v)$,后者也肯定会断掉边$(u,v)$,而现在恰好需要这条边来把两棵子树连起来,因此返还2

    一样可以滚动$$dp[u][j]=Min{dp[u][j-k]+dp[v][k]-2}$$

    初始化:$dp[u][1]=u的入度$ 注意$dp[u][0]$是没有意义的,因此不作处理

    Code

    /*By DennyQi 2018.8.14*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int MAXN = 160;
    const int MAXM = 320;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * w;
    }
    int N,P,ans(INF),x,y,first[MAXM],nxt[MAXM],to[MAXM],cnt,dp[MAXN][MAXN],rd[MAXN];
    inline void add(int u, int v){
        to[++cnt]=v,nxt[cnt]=first[u],first[u]=cnt;
        ++rd[u], ++rd[v];
    }
    inline void DP(int u, int _f){
        int v;
        for(int i = first[u]; i; i = nxt[i]){
            if((v=to[i]) == _f) continue;
            DP(v, u);
            for(int j = P; j; --j)
                for(int k = 1; k <= j; ++k)
                    dp[u][j] = Min(dp[u][j], dp[u][j-k] + dp[v][k] - 2);
        }
    }
    int main(){
        memset(dp,0x3f,sizeof(dp));
        N=r,P=r;
        for(int i = 1; i < N; ++i) x=r,y=r,add(x, y);
        for(int i = 1; i <= N; ++i) dp[i][1] = rd[i];
        DP(1, -1);
        for(int i = 1; i <= N; ++i) ans = Min(ans, dp[i][P]);
        printf("%d", ans);
        return 0;
    }
  • 相关阅读:
    设计模式-抽象工厂模式
    设计模式-工厂方法模式
    设计模式-单例
    java集合-补充HashMapJDK1.8
    java多线程-线程池
    java-阻塞队列
    java多线程-信号量
    java多线程-读写锁
    java多线程-锁
    Ubuntu下编译Poco库
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9475583.html
Copyright © 2011-2022 走看看