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 }