[IOI2005]Riv 河流

题目

题目描述
几乎整个 Byteland 王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——名叫 Bytetown。

在 Byteland 国,有 nn 个伐木的村庄,这些村庄都座落在河边。目前在 Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到 Bytetown 的伐木场。Byteland 的国王决定,为了减少运输木料的费用,再额外地建造 kk 个伐木场。这 kk 个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到 Bytetown 了,它们可以在运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。

注:所有的河流都不会分叉,形成一棵树,根结点是 Bytetown。

国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一吨木料每千米 11 分钱。

输入格式
第一行包括两个整数 n,kn,k。nn 为村庄数,kk 为要建的伐木场的数目。除了 Bytetown 外,每个村子依次被命名为 1,2,3\ldots n1,2,3…n,Bytetown 被命名为 00。

第 22 到第 (n + 1)(n+1) 行,每行 33 个整数,第 (i + 1)(i+1) 行的整数分别代表,分别表示每年 ii 村子产的木料的块数 w_iw
i

,离 ii 村子下游最近的村子 v_iv
i

(即 ii 村子的父结点),v_iv
i

到 ii 的距离 d_id
i

(千米)。

输出格式
输出最小花费,单位为分。

输入输出样例
输入 #1 复制
4 2
1 0 1
1 1 10
10 2 5
1 2 3
输出 #1 复制
4
说明/提示
数据规模与约定
对于 50%50% 的数据,保证 n\le 20n≤20。
对于 100%100% 的数据,保证 2\le n\le 1002≤n≤100,1\le k\le \min(n,50)1≤k≤min(n,50),0\le v_i\le n0≤v
i

≤n,0\le w_i\le 10^40≤w
i

≤10
4
,1\le d_i\le 10^41≤d
i

≤10
4

保证每年所有的木料流到 bytetown 的运费不超过 2\times 10^92×10
9
分。

思路

F[i][j][k]表示以i为根的树,j是i的某个祖先,j上有伐木场,i和i的子树一共用了k个伐木场所需要的最小费用。

我们可以开两个数组,f表示i没建,g表示i建了伐木场。为了方便最后用f表示答案即可。

代码

#include<bits/stdc++.h>
using namespace std;

void Read(int &x)
{
    x = 0;
    char a = getchar();
    bool f = 0;
    while(a < '0'||a > '9') {if(a == '-') f = 1;a = getchar();}
    while(a >= '0'&&a <= '9') {x = x * 10 + a - '0';a = getchar();}
    if(f) x *= -1;
}
const int MAXN = 202;
vector<int> G[MAXN],Road[MAXN];
int maxk,wood[MAXN],ancestor[MAXN],tot,dep[MAXN],dp[MAXN][MAXN][52][2];
bool vis[MAXN];


template<typename T>
T Min(T a,T b) {if(a < b) return a;return b;}
void dfs(int x)
{
    int i,j,k,l;;
    ancestor[++tot] = x;
    for(i = 0;i < G[x].size();i++)
    {
        int v = G[x][i],w = Road[x][i];
        if(!vis[v])
        {
            vis[v] = 1;
            dep[v] = dep[x] + w; 
            dfs(v);
            for(j = tot;j >= 1;j--)
            {
                int fa = ancestor[j];
                for(k = maxk;k >= 0;k--)
                {
                    dp[x][fa][k][0] += dp[v][fa][0][0];
                    dp[x][fa][k][1] += dp[v][x][0][0];
                    for(l = k;l >= 0;l--)
                    {
                        dp[x][fa][k][0] = Min(dp[x][fa][k][0],dp[v][fa][l][0] + dp[x][fa][k - l][0]);
                        dp[x][fa][k][1] = Min(dp[x][fa][k][1],dp[v][x][l][0] + dp[x][fa][k - l][1]);    
                    }
                }
            }
        }
    }
    for(i = 1;i <= tot;i++)
    {
        int fa = ancestor[i];
        for(j = maxk;j >= 0;j--)
        {
            if(j >= 1)
                dp[x][fa][j][0] = Min(dp[x][fa][j][0] + wood[x] * (dep[x] - dep[fa]),dp[x][fa][j - 1][1]);
            else dp[x][fa][j][0] += wood[x] * (dep[x] - dep[fa]);
        }
    }
    tot--;
}
int main()
{
    int n,i;
    Read(n),Read(maxk);
    for(i = 1;i <= n;i++)
    {
        int v,dis;
        Read(wood[i]),Read(v),Read(dis);
        G[i].push_back(v);
        G[v].push_back(i);
        Road[i].push_back(dis);
        Road[v].push_back(dis);
    }
    vis[0] = 1;
    dfs(0);
    printf("%d",dp[0][0][maxk][0]);
    return 0;
}
发布了809 篇原创文章 · 获赞 396 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/105509281