【洛谷P1272】 重建道路

重建道路

题目链接

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

显然是一道树形DP

然后看题解

树上分组背包问题

dp[u][i][j]表示以u为根的子树中,前i个子树中留下j个的最小花费

首先,dp[u][size[u]][1]=son_num[u]

以u为节点的子树留下1个节点的花费为u的子树个数

dp[u][i][j]=min(dp[u][i][j],dp[u][i-1][j-k]+dp[v][size[v]][k]-1);

i这一维可以滚动数组滚掉

#include<iostream>
#include<cstring>
#include<cstdio> 
#define N 155
int n,p,dp[N][N],out[N],in[N];
struct NODE{
    int to,next;
} e[N];
int Head[N],num;
inline void add(int x,int y){
    e[++num].to=y;
    e[num].next=Head[x];
    Head[x]=num;
}
inline int read(){
    int x=0; char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
    return x;
}
inline int min(int a,int b){
    return a<b?a:b;
}
int dfs(int u){
    dp[u][1]=out[u];
    int sum=1;
    for(int i=Head[u];i;i=e[i].next){
        int v=e[i].to;
        int sz=dfs(v); sum+=sz;
        for(int j=sum;j>=0;j--)
         for(int k=0;k<=min(sz,j);k++){
          dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]-1);
        }
    }
    dp[u][sum]=0;
    return sum;
}
int main()
{
    memset(dp,0x3f,sizeof(dp));
    scanf("%d%d",&n,&p);
    int x,y;
    for(int i=1;i<n;i++){
        x=read(); y=read();
        add(x,y);
        out[x]++; in[y]++;
    }
    int st;
    for(int i=1;i<=n;i++)
     if(!in[i]) {
         st=i; break;
     }
    dfs(st);
    int ans=0x7fffffff;
    for(int i=1;i<=n;i++)
     ans=min(ans,dp[i][p]+(i==st?0:1));
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/yjkhhh/p/9415758.html
今日推荐