noi 2009 二叉查找树 动态规划

思路:

先把权值离散化

按数据值排序

sum[i]为前i个节点频度和

dp[i][j][w]表示把节点[i,j]合并成一颗根节点权值不小于w的子树所需的访问代价与修改代价的最小和

dp[i][j][w]=min(dp[i][k-1][w]+dp[k+1][j][w]+sum[j]-sum[i-1]+K,dp[i][k-1][a[k].weight]+dp[k+1][j][a[k].weight]+sum[j]-sum[i-1](a[k].weight>=w))

(i<=k<=j)

ans=dp[1][n][1];

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<map>
 6 #include<algorithm>
 7 using namespace std;
 8 #define MAXN 80
 9 #define INF 987654321
10 int n,m;
11 struct node
12 {
13     int key,weight,frequence;
14 }a[MAXN];
15 int sum[MAXN];
16 int dp[MAXN][MAXN][MAXN];
17 bool cmp1(const node &A,const node &B)
18 {
19     return A.weight<B.weight;
20 }
21 bool cmp2(const node &A,const node &B)
22 {
23     return A.key<B.key;
24 }
25 int main()
26 {
27     memset(dp,0,sizeof(dp));
28     scanf("%d%d",&n,&m);
29     int i,j,k,w,t;
30     for(i=1;i<=n;i++)
31         scanf("%d",&a[i].key);
32     for(i=1;i<=n;i++)
33         scanf("%d",&a[i].weight);
34     for(i=1;i<=n;i++)
35         scanf("%d",&a[i].frequence);
36     sort(a+1,a+n+1,cmp1);
37     for(i=1;i<=n;i++)
38         a[i].weight=i;
39     sort(a+1,a+n+1,cmp2);
40     sum[0]=0;
41     for(i=1;i<=n;i++)
42         sum[i]=sum[i-1]+a[i].frequence;
43     for(i=1;i<=n;i++)
44         for(j=1;j<=n;j++)
45         {
46             if(a[i].weight>=j)
47                 dp[i][i][j]=a[i].frequence;
48             else
49                 dp[i][i][j]=a[i].frequence+m;
50         }
51     for(w=n;w>=1;w--)
52     for(t=1;t<n;t++)
53     for(i=1;i+t<=n;i++)
54     {
55         j=i+t;
56         int s=INF;
57         for(k=i;k<=j;k++)
58         {
59                 s=min(s,dp[i][k-1][w]+dp[k+1][j][w]+sum[j]-sum[i-1]+m);
60                 if(a[k].weight>=w)
61                     s=min(s,dp[i][k-1][a[k].weight]+dp[k+1][j][a[k].weight]+sum[j]-sum[i-1]);
62         }
63         dp[i][j][w]=s;
64     }
65     int s=INF;
66     printf("%d\n",dp[1][n][1]);
67     return 0;
68 }
原文地址:https://www.cnblogs.com/myoi/p/2592942.html