重建道路

Posted 大飞的小屋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重建道路相关的知识,希望对你有一定的参考价值。

传送门啦

题意是删除一些边使原图剩P个节点,那么我们在进行树形dp的时候就要考虑这条是不是删,但这样就不太好转移。

那么我们转化一下,假设把所有的边先都删除,那么我们要考虑这条边是不是要加进去,这要就好转移多了,就是一个背包+树形dp。

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

inline int read(){
    char ch = getchar();
    int f = 1 , x = 0;
    while(ch > 9 || ch < 0){if(ch == 0) f = -1;ch = getchar();}
    while(ch >= 0 && ch <= 9){x = (x << 1) + (x << 3) + ch - 0; ch = getchar();}
    return x * f;
}

int n,p,u,v;
struct Edge{
    int from,to,next;
}edge[200 * 2];
int head[200],tot;
int du[200],f[200][200],ans=1e9;
//f[i][j]:表示以i为根的子树里面截取j个节点的最少删边数

void add(int u,int v){
    edge[++tot].from = u;
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot;
}

void dfs(int x,int fa){
    if(fa != 0)  f[x][1] = du[x] - 1;
    else f[x][1] = du[x];
    for(int i=head[x];i;i=edge[i].next){
        int v = edge[i].to;
        if(v != fa){
            dfs(v , x);
            for(int j=p;j>=1;j--)
              for(int k=1;k<j;k++)
                f[x][j] = min(f[x][j] , f[x][k] + f[v][j-k] - 1);
                //减1因为一开始把所有的边都删了 
        }
    }
    if(fa != 0)  ans = min(ans , f[x][p] + 1);
    else ans = min(ans , f[x][p]);
}

int main(){
    n = read(); p = read();
    for(int i=1;i<=n-1;i++){
        u = read(); v = read();
        add(u , v); add(v , u);
        du[u]++;  du[v]++; 
    }
    memset(f , 0x3f , sizeof(f));
    dfs(1 , 0);
    printf("%d\n",ans);
    return 0;
}

 

以上是关于重建道路的主要内容,如果未能解决你的问题,请参考以下文章

洛谷——P3905 道路重建

洛谷 P3905 道路重建

luogu P1272 重建道路

道路重建(拓扑+贪心)

重建道路

P1272 重建道路(树形dp)