BZOJ1812: [ioi2005]riv (树形Dp)

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

解题思路:

三维树形dp还是很神的。
dp[i][j][k]表示在第 i 号节点最近祖先伐木场为 j 子树中有 k 个伐木场的最小距离。
这居然完美滴解决了其他方程不优或有后效性的缺点。
代码:
 
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef long long lnt;
 5 struct pnt{
 6     int hd;
 7     int fa;
 8     lnt val;
 9     lnt dis[5000];
10     lnt dp[500][60];
11 }p[500];
12 struct ent{
13     int twd;
14     int lst;
15 }e[10000];
16 int cnt;
17 int n,K;
18 void ade(int f,int t)
19 {
20     cnt++;
21     e[cnt].twd=t;
22     e[cnt].lst=p[f].hd;
23     p[f].hd=cnt;
24     return ;
25 }
26 void Dfs(int x)
27 {
28     int lst=x;
29     for(int i=p[x].fa;i;i=p[i].fa)
30     {
31         p[x].dis[i]=p[x].dis[lst]+p[lst].dis[i];
32         lst=i;
33     }
34     if(!p[x].hd)
35     {
36         for(int i=p[x].fa;i;i=p[i].fa)
37         {
38             p[x].dp[i][0]=p[x].dis[i]*p[x].val;
39         }
40         return ;
41     }
42     if(x!=1)
43         p[x].dp[x][0]=0x3f3f3f3f;
44     for(int i=p[x].hd;i;i=e[i].lst)
45     {
46         int to=e[i].twd;
47         Dfs(to);
48         for(int j=p[x].fa;j;j=p[j].fa)
49         {
50             for(int k=K;k>=0;k--)
51             {
52                 lnt tmp=0x3f3f3f3f;
53                 for(int h=0;h<=k;h++)
54                     tmp=std::min(tmp,p[x].dp[j][h]+p[to].dp[j][k-h]);
55                 p[x].dp[j][k]=tmp;
56             }
57         }
58         for(int j=K;j>=0;j--)
59         {
60             lnt tmp=0x3f3f3f3f;
61             for(int k=0;k<=j;k++)
62                 tmp=std::min(tmp,p[x].dp[x][k]+p[to].dp[x][j-k]);
63             p[x].dp[x][j]=tmp;
64         }
65     }
66     for(int i=p[x].fa;i;i=p[i].fa)
67     {
68         for(int j=0;j<=K;j++)
69         {
70             p[x].dp[i][j]+=p[x].dis[i]*p[x].val;
71             p[x].dp[i][j]=std::min(p[x].dp[i][j],p[x].dp[x][j]);
72         }
73     }
74     return ;
75 }
76 int main()
77 {
78     scanf("%d%d",&n,&K);
79     n++;
80     for(int i=2;i<=n;i++)
81     {
82         lnt a,b;
83         int c;
84         scanf("%lld%d%lld",&a,&c,&b);
85         c++;
86         p[i].fa=c;
87         p[i].dis[c]=b;
88         p[i].val=a;
89         ade(p[i].fa,i);
90     }
91     Dfs(1);
92     printf("%lld\n",p[1].dp[1][K]);
93     return 0;
94 }

 

posted @ 2018-10-04 11:02  Unstoppable728  阅读(238)  评论(0编辑  收藏  举报