[LUOGU] P3354 [IOI2005]Riv 河流

題目描述
幾乎整個Byteland王國都被森林和河流所覆蓋。小點的河匯聚到一起,形成了稍大點的河。就這樣,所有的河水都匯聚並流進了一條大河,最後這條大河流進了大海。這條大河的入海口處有一個村莊——名叫Bytetown。

在Byteland國,有n個伐木的村莊,這些村莊都座落在河邊。目前在Bytetown,有一個巨大的伐木場,它處理着全國砍下的所有木料。木料被砍下後,順着河流而被運到Bytetown的伐木場。Byteland的國王決定,爲了減少運輸木料的費用,再額外地建造k個伐木場。這k個伐木場將被建在其他村莊裏。這些伐木場建造後,木料就不用都被送到Bytetown了,它們可以在運輸過程中第一個碰到的新伐木場被處理。顯然,如果伐木場座落的那個村子就不用再付運送木料的費用了。它們可以直接被本村的伐木場處理。

注:所有的河流都不會分叉,形成一棵樹,根結點是Bytetown。

國王的大臣計算出了每個村子每年要產多少木料,你的任務是決定在哪些村子建設伐木場能獲得最小的運費。其中運費的計算方法爲:每一噸木料每千米1分錢。

輸入輸出格式
輸入格式:
第一行包括兩個數 n(2≤n≤100),k(1≤k≤50,且 k≤n)。n爲村莊數,k爲要建的伐木場的數目。除了Bytetown外,每個村子依次被命名爲123……n,Bytetown被命名爲0。

接下來n行,每行3個整數:

wi——每年i村子產的木料的塊數(0≤wi≤10000)

vi——離i村子下游最近的村子(即i村子的父結點)(0≤vi≤n)

di——vi到i的距離(千米)。(1≤di≤10000)

保證每年所有的木料流到bytetown的運費不超過2,000,000,00050%的數據中n不超過20。

輸出格式:
輸出最小花費,單位爲分。

輸入輸出樣例
輸入樣例#1: 
4 2
1 0 1
1 1 10
10 2 5
1 2 3
輸出樣例#1: 
4

樹上分組揹包+約定祖先

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

inline int rd() {
    int ret=0,f=1;
    char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=155;

struct Edge {
    int next,to,w;
} e[MAXN];
int ecnt,head[MAXN];
inline void add(int x,int y,int w) {
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    e[ecnt].w = w;
    head[x] = ecnt;
}

int n,k;
int val[MAXN];
int f[MAXN][MAXN][MAXN];
int g[MAXN][MAXN][MAXN];
int stack[MAXN],top;
int dep[MAXN];

void dfs(int x) {
    stack[++top]=x;
    for(int i=head[x]; i; i=e[i].next) {
        int v=e[i].to;
        dep[v]=dep[x]+e[i].w;
        dfs(v);
        for(int fa=1; fa<=top; fa++) {
            for(int j=k; j>=0; j--) {
                f[x][j][stack[fa]]+=f[v][0][stack[fa]];
                g[x][j][stack[fa]]+=f[v][0][x];
                for(int u=0; u<=j; u++) {//
                    f[x][j][stack[fa]]=min(f[x][j][stack[fa]],f[x][j-u][stack[fa]]+f[v][u][stack[fa]]);
                    g[x][j][stack[fa]]=min(g[x][j][stack[fa]],g[x][j-u][stack[fa]]+f[v][u][x]);
                }
            }
        }
    }
    for(int fa=1; fa<=top; fa++) {
        for(int j=0; j<=k; j++) {
            if(j>=1) f[x][j][stack[fa]]=min(f[x][j][stack[fa]]+val[x]*(dep[x]-dep[stack[fa]]),g[x][j-1][stack[fa]]);
            else f[x][j][stack[fa]]+=val[x]*(dep[x]-dep[stack[fa]]);
        }
    }


    top--;
}

int main() {
    n=rd();
    k=rd();
    for(int i=1; i<=n; i++) {
        int y,w;
        val[i]=rd();
        y=rd();
        w=rd();
        add(y,i,w);
    }
    dfs(0);
    cout<<f[0][k][0];
    return 0;
}
發佈了180 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章