给一棵二叉树,每个叶子节点 \(i\) 有三个属性 \(a_i,b_i,c_i\)

每个非叶子节点都能标记向左右儿子中的一条边(记作 \(x\) 边和 \(y\) 边)

设叶子节点 \(i\) 到根的路径上有 \(p\) 条没被标记的 \(x\) 边,\(q\) 条没被标记的 \(y\)

那么 \(i\) 的花费就是 \(c_i\times (a_i+p)\times (b_i+q)\)

最小化这个花费

传说中的pj难度题

这个式子有点吓人啊

定义 \(f[i][j][k]\) 表示 \(i\) 到根的路径上,有 \(j\) 条没被标记的 \(x\) 边, \(k\) 条没被标记的 \(y\)\(i\) 的最小花费

对于叶子节点,直接枚举 \(x\)\(y\) 边各有多少条

对于非叶节点,左右儿子选择一条标记取最小值就行了

等等,我们来算一下空间复杂度

第一维要开 \(2n\),第二第三维至少要开 \(41\),又因为答案会爆 \(int\),所以要开 \(long\;long\)

那么光 \(f\) 数组的空间占用就是 \(40010*1600*8/1024/1024 \approx 488M\),显然不够用

我们考虑二叉树的性质,一个点的 \(f\) 值只用知道它的左右儿子的 \(f\) 值即可,又因为最多只有 \(\log n\) 层,所以我们动态分配内存,这样下来空间复杂度就是 \(O(\log n*1600)\) 了。

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<cstring>
  4. #define N 20005
  5. #define in inline
  6. typedef long long ll;
  7. #define re register signed
  8. #define min(A,B) ((A)<(B)?(A):(B))
  9. #define max(A,B) ((A)>(B)?(A):(B))
  10. #define swap(A,B) ((A)^=(B)^=(A)^=(B))
  11. //一颗二叉树 f[i][j][k]->refers from 1 to i,still has j highway,k railway,mininum cost
  12. int n,cnt;
  13. int ch[N][2];
  14. int stk[N],top;
  15. ll f[100][45][45];
  16. int a[N],b[N],c[N];
  17. int hi[N<<1],ri[N<<1];
  18. //要压空间 sb题
  19. //开栈 最多logn
  20. in int getint(){
  21. int x=0,f=0;char ch=getchar();
  22. while(!isdigit(ch)) f|=ch=='-',ch=getchar();
  23. while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  24. return f?-x:x;
  25. }
  26. in int newnode(){
  27. return top?stk[top--]:++cnt;
  28. }
  29. void dp(int now,int d,int k){
  30. if(now>n){
  31. for(int i=0;i<=hi[now];i++){
  32. for(int j=0;j<=ri[now];j++)
  33. f[k][i][j]=(ll)c[now-n]*(a[now-n]+i)*(b[now-n]+j);
  34. }
  35. return;
  36. }
  37. int x=newnode();
  38. int y=newnode();
  39. dp(ch[now][0],0,x);
  40. dp(ch[now][1],1,y);
  41. for(re i=0;i<=hi[now];i++){
  42. for(re j=0;j<=ri[now];j++)
  43. f[k][i][j]=min(f[x][i][j]+f[y][i][j+1],f[x][i+1][j]+f[y][i][j]);
  44. }
  45. stk[++top]=x;stk[++top]=y;
  46. /* puts("");
  47. printf("now=%d\n",now);
  48. for(int i=0;i<=hi[now];i++){
  49. for(int j=0;j<=ri[now];j++)
  50. printf("i=%d,j=%d,f=%lld\n",i,j,f[k][i][j]);
  51. }*/
  52. }
  53. void dfs(int now,int x,int y){
  54. if(now>n){hi[now]=x;ri[now]=y;return;}
  55. if(ch[now][0]) dfs(ch[now][0],x+1,y);
  56. if(ch[now][1]) dfs(ch[now][1],x,y+1);
  57. hi[now]=x;ri[now]=y;
  58. }
  59. signed main(){
  60. n=getint();
  61. for(re i=1;i<n;i++){
  62. int x=getint(),y=getint();
  63. if(x<0) x=n-x;
  64. if(y<0) y=n-y;
  65. ch[i][0]=x;ch[i][1]=y; //leftson->highway rightson->railway
  66. }
  67. for(re i=1;i<=n;i++)
  68. a[i]=getint(),b[i]=getint(),c[i]=getint();
  69. dfs(1,0,0);
  70. int x=newnode();
  71. dp(1,0,x);
  72. printf("%lld\n",f[x][0][0]);
  73. return 0;
  74. }

版权声明:本文为YoungNeal原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/YoungNeal/p/9379907.html