Description
几乎整个 Byteland 王国都被森林和河流所覆盖. 小点的河汇聚到一起, 形成了稍大点的河. 就这样, 所有的河水都汇聚并流进了一条大河, 最后这条大河流进了大海. 这条大河的入海口处有一个村庄 -- 名叫 Bytetown 在 Byteland 国, 有 n 个伐木的村庄, 这些村庄都座落在河边. 目前在 Bytetown, 有一个巨大的伐木场, 它处理着全国砍下的所有木料. 木料被砍下后, 顺着河流而被运到 Bytetown 的伐木场. Byteland 的国王决定, 为了减少运输木料的费用, 再额外地建造 k 个伐木场. 这 k 个伐木场将被建在其他村庄里. 这些伐木场建造后, 木料就不用都被送到 Bytetown 了, 它们可以在 运输过程中第一个碰到的新伐木场被处理. 显然, 如果伐木场座落的那个村子就不用再付运送木料的费用了. 它们可以直接被本村的伐木场处理. 注意: 所有的河流都不会分叉, 也就是说, 每一个村子, 顺流而下都只有一条路 -- 到 bytetown. 国王的大臣计算出了每个村子每年要产多少木料, 你的任务是决定在哪些村子建设伐木场能获得最小的运费. 其中运费的计算方法为: 每一块木料每千米 1 分钱. 编一个程序: 1.从文件读入村子的个数, 另外要建设的伐木场的数目, 每年每个村子产的木料的块数以及河流的描述. 2.计算最小的运费并输出.
Input
第一行 包括两个数 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 村子下游最近的村子 (或 bytetown)(0<=vi<=n) di--vi 到 i 的距离 (km).(1<=di<=10000) 保证每年所有的木料流到 bytetown 的运费不超过 2000,000,000 分 50%的数据中 n 不超过 20.
Output
输出最小花费, 精确到分.
- Sample Input
- 4 2
- 1 0 1
- 1 1 10
- 10 2 5
- 1 2 3
- Sample Output
- 4
这题绝对好题, 看了 https://www.cnblogs.com/CQzhangyu/p/7605481.html https://www.cnblogs.com/CQzhangyu/p/7605481.html 后才明白怎么转移的.
设 F[i][j][k] 表示以 i 为根的子树中, 建了 k 个伐木场, i 的祖先最近的一个建伐木场的位置到 i 的距离为 j.
这样我们把代价提前计算.
转移类似背包, 按子树合并, dfs 中更新祖先.
F[i][j][k+l]=F[i][j][k]+min(F[son][j][l],F[son][0][l]), 分别表示儿子不放 / 放伐木场.
代码:
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- #define N 205
- int head[N],to[N],nxt[N],val[N],w[N],cnt,fa[N][N],siz[N],sf[N],dis[N],g[N][N],m,n;
- int f[N][N][N];
- inline void add(int u,int v,int z) {
- to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=z;
- }
- void dfs(int x) {
- int i,j,k,l;siz[x]=1;
- fa[x][0]=x;
- for(i=0;i<=sf[x];i++) {
- f[x][i][!i]=(dis[x]-dis[fa[x][i]])*w[x];
- }
- for(i=head[x];i;i=nxt[i]) {
- dis[to[i]]=dis[x]+val[i];
- for(j=0;j<=sf[x];j++) fa[to[i]][++sf[to[i]]]=fa[x][j];
- dfs(to[i]);
- memset(g,0x3f,sizeof(g));
- for(j=0;j<=sf[x];j++) {
- for(k=min(m,siz[x]);k>=0;k--) {
- for(l=min(m-k,siz[to[i]]);l>=0;l--) {
- g[j][k+l]=min(g[j][k+l],f[x][j][k]+min(f[to[i]][j+1][l],f[to[i]][0][l]));
- }
- }
- }
- siz[x]+=siz[to[i]];
- for(j=0;j<=sf[x];j++) {
- for(k=min(m,siz[x]);k>=0;k--) {
- f[x][j][k]=g[j][k];
- }
- }
- }
- }
- int main() {
- memset(f,0x3f,sizeof(f));
- // freopen("riv.in","r",stdin);
- // freopen("riv.out","w",stdout);
- scanf("%d%d",&n,&m);m++;
- int i,z;
- for(i=1;i<=n;i++) {
- scanf("%d%d%d",&w[i],&fa[i][1],&z);
- add(fa[i][1],i,z);
- }
- dfs(0);
- printf("%d\n",f[0][0][m]);
- }
- /*
- 4 2
- 1 0 1
- 1 1 10
- 10 2 5
- 1 2 3
- */
- /*
- 8 2
- 233 0 5
- 9 1 80
- 27 2 20
- 64 1 100
- 2 3 14
- 81 4 5
- 10 3 70
- 10 5 8
- */
来源: http://www.bubuko.com/infodetail-2651790.html