Factories(树上背包转移 树形dp)

original link - https://nanti.jisuanke.com/t/41291

题意:

给出一棵树,你需要选择KKK个叶子,使得两两距离和最小。

解析:

考虑从儿子到父亲的转移,用dp[i][j]dp[i][j]dp[i][j]记录iii的子树中,选取jjj个叶子的预期最小距离。

转移的时候用背包进行转移,将dp[son][h]dp[son][h]dp[son][h]当作一个物品,做只能选择一个物品的01包即可。

dp[fa][j]+dp[son][h]+lengthedgeh(kh))dp[fa][j+h]dp[fa][j]+dp[son][h]+length_{edge}*h*(k-h))\to dp[fa][j+h]dp[fa][j]+dp[son][h]+lengthedge​∗h∗(k−h))→dp[fa][j+h]

父亲已经有jjj条,我现在连入hhh条,对将来所产生的贡献为lengthedgeh(kh)length_{edge}*h*(k-h)lengthedge​∗h∗(k−h),因为一共会有h(kh)h*(k-h)h∗(k−h)对点经过这条边。

极限数据卡不到1e61001001e6*100*1001e6∗100∗100
Factories(树上背包转移 树形dp)
因为每个点的转移状态都是现有状态*儿子状态,均摊下来不会很大(上面的情况每个点只有1*100)

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2019-08-31-20.11.43
 */
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<<x<<'\n';
const LL mod=1e9+7;
const int maxn=1e5+9;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
/*_________________________________________________________head*/

#define rep_e(i,p,u) for(int i=head[p],u=to[i];i;i=nex[i],u=to[i])
int head[maxn],to[maxn<<1],nex[maxn<<1],val[maxn<<1],now;
void add(int a,int b,int v){
    nex[++now]=head[a];head[a]=now;to[now]=b,val[now]=v;
}
void init_edge(){
    memset(head,0,sizeof head);
    now=0;
}
/*_________________________________________________________edge*/

const LL inf=2e18;
int n,k;
int deg[maxn];
int siz[maxn];
LL dp[maxn][104];

void dfs(int p,int fa){
    dp[p][0]=0;
    siz[p]=0;
    int lef=1;
    rep_e(i,p,u){
        if(u==fa)continue;
        lef=0;
        dfs(u,p);
        siz[p]+=siz[u];
        per(j,k-1,0){
            if(dp[p][j]==inf)continue;
            int up=min(k-j,siz[u]);
            rep(h,1,up){
                dp[p][j+h]=min(dp[p][j+h],dp[p][j]+dp[u][h]+val[i]*h*(k-h));
            }
        }
    }
    if(lef){
        siz[p]=1;
        dp[p][1]=0;
    }
}

int main(){
    int t=rd(),cas=0;
    while(t--){
        init_edge();
        mmm(deg,0);
        n=rd(),k=rd();
        rep(i,1,n)
            rep(j,0,k)
                dp[i][j]=inf;
        rep(i,1,n-1){
            int a=rd(),b=rd(),v=rd();
            add(a,b,v),add(b,a,v);
            deg[a]++,deg[b]++;
        }
        int rt=1;
        rep(i,1,n){
            if(deg[i]>1){rt=i;break;}
        }
        if(n==2){
            if(k==1)printf("Case #%d: %d\n",++cas,0);
            else printf("Case #%d: %d\n",++cas,val[1]);
            continue;
        }
        dfs(rt,-1);
        printf("Case #%d: %lld\n",++cas,dp[rt][k]);
    }
    return 0;
}

上一篇:汇编语言学习记录01丨开发工具安装及编译运行第一个程序


下一篇:汇编Hello,world.