IOI2005河流

题目描述

几乎整个Byteland王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——名叫Bytetown
在Byteland国,有n个伐木的村庄,这些村庄都座落在河边。目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到Bytetown的伐木场。Byteland的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场。这k个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到Bytetown了,它们可以在 运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。
注意:所有的河流都不会分叉,也就是说,每一个村子,顺流而下都只有一条路——到bytetown。
国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一块木料每千米1分钱。
编一个程序:
1.从文件读入村子的个数,另外要建设的伐木场的数目,每年每个村子产的木料的块数以及河流的描述。
2.计算最小的运费并输出。
输入
第1行:包括两个数 n(2<=n<=100),k(1<=k<=50,且 k<=n)。n为村庄数,k为要建的伐木场的数目。除了bytetown外,每个村子依次被命名为1,2,3……n,bytetown被命名为0。
接下来n行,每行3个整数 wi——每年i村子产的木料的块数 (0<=wi<=10000) vi——离i村子下游最近的村子(即i村子的父结点)(0<=vi<=n) di——vi到i的距离(千米)。(1<=di<=10000)
保证每年所有的木料流到bytetown的运费不超过2000,000,000分 50%的数据中n不超过20。
输出
输出最小花费,精确到分。
样例输入
4 2
1 0 1
1 1 10
10 2 5
1 2 3
样例输出
4

分析

树形结构并且求出最小代价,我们很容易想到树形DP,并且放 k 个伐木场才会有最小代价。
求出最小花费,需要确定这 k 个伐木场放在哪里。
考虑DP的状态定义,如果像之前定义的DP[u][j] 为以u为根节点的子树上放 j 个伐木场的最小代价,很快发现这样定义没有办法转移,因为我们不知道根节点是否放置了伐木场,那么,是否可以增加一个 0 1 维度表示根节点有无伐木场呢?显然,当前根节点不放置伐木场时,最小代价无法求出,因为我们不知道这个点的木材会送到哪里处理。
所以,我们可以定义DP[u][v][j]表示在以u为根节点的子树上放 j 个伐木场,且 u 能到达的最近的伐木场 v(包括 u)的最小代价。
状态转移:DP[u][v][j]=min(sum{dp[son of u][v][j’]}) (sum j’ = j )
这道题如果写多叉树的DP,实现过程会非常复杂,所以需要多叉转二叉(左儿子,右兄弟)。
最终状态转移:
若u点不放伐木场:
DP[u][v][j]=min(DP[lch][v][[j’]+DP[rch][v][j-j’]+w[u]*d[u][v]);
u点不放伐木场,所以要加上u->v的代价。
若u点放伐木场:
DP[u][v][j]=min(DP[lch][u][[j’]+DP[rch][v][j-j’-1]);

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 100
#define MAXK 50
#define INF 0x3f3f3f3f
struct node
{
    int lch,rch,num,d;
}e[MAXN+5];
int d[MAXN+5],fa[MAXN+5];
int ch[MAXN+5],ta[MAXN+5],r;
int dp[MAXN+5][MAXN+5][MAXK+5];
int n,K;
void DFS(int u,int dl)
{
    ta[++r]=u;
    d[u]=dl+e[u].d;
    for(int i=e[u].lch;i;i=e[i].rch)
        DFS(i,d[u]);
}
int main()
{
    scanf("%d%d",&n,&K);
    fa[0]=-1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&e[i].num,&fa[i],&e[i].d);
        if(!ch[fa[i]])
            e[fa[i]].lch=i;
        else e[ch[fa[i]]].rch=i;
        ch[fa[i]]=i;
    }
    DFS(0,0);
    memset(dp,INF,sizeof dp);
    memset(dp[0],0,sizeof dp[0]);
    for(int i=r;i>1;i--)
    {
        int u=ta[i];
        int ls=e[u].lch,rs=e[u].rch;
        for(int j=fa[u];j!=-1;j=fa[j])
            for(int k=0;k<=K;k++)
            {
                for(int l=0;l<=k;l++)
                    if(dp[ls][j][l]!=INF&&dp[rs][j][k-l]!=INF)
                        dp[u][j][k]=min(dp[u][j][k],dp[ls][j][l]+dp[rs][j][k-l]+e[u].num*(d[u]-d[j]));
                for(int l=0;l<k;l++)
                    if(dp[ls][u][l]!=INF&&dp[rs][j][k-l-1]!=INF)
                        dp[u][j][k]=min(dp[u][j][k],dp[ls][u][l]+dp[rs][j][k-l-1]);
            }
    }
    printf("%d\n",dp[e[0].lch][0][K]);
}

猜你喜欢

转载自blog.csdn.net/qq_41343943/article/details/79587322