#树形dp#洛谷 3354 河流

题目

一颗有N+1个结点的树,树中的每个结点可能会生产出一些产品。这些产品要么就地加工(要有加工厂才行),要么运送到它的父亲结点那儿去。现在在整棵树的根结点处已经有了一个产品加工厂,而且所有的产品最终必须在某个加工厂加工才行。由于运费昂贵,不可能将所有的产品都运送到根节点处加工。现在决定在树中的某些结点新增总共K个加工厂,现在要你选择这K个加工厂的厂址。


分析

树形dp,用兄弟孩子表示法,
f [ x ] [ i + j ] [ p ] = m i n ( f [ x ] [ i + j ] [ p ] , f [ s o n 1 ] [ i ] [ p + 1 ] + f [ s o n 2 ] [ j ] [ p ] + w [ x ] d i s [ x ] [ p ] )
f [ x ] [ i + j + 1 ] [ p ] = m i n ( f [ x ] [ i + j + 1 ] [ p ] , f [ s o n 1 ] [ i ] [ 1 ] + f [ s o n 2 ] [ j ] [ p ] )


代码

#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
int n,k,w[102],fa[102],d[102],f[102][102][102],bro[102],son[102],dis[102][102];
int in(){
    int ans=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans;
}
int min(int a,int b){return (a<b)?a:b;}
void dp(int x,int limi){
    int x1=son[x],x2=bro[x];
    for (int i=1;i<=limi;i++) dis[x][i]=dis[fa[x]][i-1]+d[x];
    if (x1) dp(x1,limi+1); if (x2) dp(x2,limi);
    for (int i=0;i<=n;i++)
    for (int j=0;j<=n-i;j++)
    for (int p=1;p<=limi;p++)
    f[x][i+j][p]=min(f[x][i+j][p],f[x1][i][p+1]+f[x2][j][p]+w[x]*dis[x][p]),
    f[x][i+j+1][p]=min(f[x][i+j+1][p],f[x1][i][1]+f[x2][j][p]);
}
int main(){
    n=in(); k=in();
    for (int i=1;i<=n;i++){
        w[i]=in(); fa[i]=in(); d[i]=in();
        bro[i]=son[fa[i]]; son[fa[i]]=i;
    }
    memset(f,0x7f,sizeof(f));
    for (int i=0;i<=n;i++)
    for (int j=0;j<=n;j++) f[0][i][j]=0;
    dp(son[0],1); return !printf("%d",f[son[0]][k][1]); 
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/81055329