关于树形背包DP的时间复杂度证明
例题——洛谷P2014 [CTSC1997] 选课
代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> a[305];
int s[305],dp[305][305],si[305];
void dfs(int x)
{si[x]=1; dp[x][1]=s[x];for(int i=0;i<a[x].size();i++){dfs(a[x][i]);for(int p=min(si[x],m);p>=1;p--)for(int j=min(si[a[x][i]],m-p);j>=0;j--)dp[x][j+p]=max(dp[x][j+p],dp[x][p]+dp[a[x][i]][j]);si[x]+=si[a[x][i]];}
}
int main()
{cin>>n>>m;m++;for(int i=1;i<=n;i++){int k;cin>>k>>s[i];a[k].push_back(i);}dfs(0);cout<<dp[0][m];return 0;
}
大家不要认为是是 O(n3)O(n^3)O(n3),如果优化得当可以达到 O(n2)O(n^2)O(n2)(如上方程序)。
证明
对于每个点,都是其儿子的子树大小两两相乘(子树不与本身相乘!)的复杂度:
∑i=1n∑j=son(sj∗∑k=sonk<jsk)\sum_{i=1}^{n} \sum_{j=son}^{} (s_{j}*\sum_{k=son}^{k< j}s_{k})∑i=1n∑j=son(sj∗∑k=sonk<jsk)
因为 ∑k=sonsk=si−1\sum_{k=son}^{}s_{k}=s_{i}-1∑k=sonsk=si−1
所以 ∑i=1n∑j=sonsj∗∑k=sonk<jsk=∑i=1n∑j=sonsj∗(si−1−sj)2=−∑i=2nsi2+∑i=1nsi∗(si−1)2−∑i=2nsi∗si2(这里不包含根节点)\sum_{i=1}^{n} \sum_{j=son}^{} s_{j}*\sum_{k=son}^{k<j}s_{k} =\frac{\sum_{i=1}^{n} \sum_{j=son}^{}s_{j}*(s_{i}-1-s_{j})}{2}=-\frac{\sum_{i=2}^{n}s_{i} }{2}+ \frac{\sum_{i=1}^{n} s_{i}*(s_{i}-1)}{2}- \frac{\sum_{i=2}^{n} s_{i}*s_{i}}{2}(这里不包含根节点)∑i=1n∑j=sonsj∗∑k=sonk<jsk=2∑i=1n∑j=sonsj∗(si−1−sj)=−2∑i=2nsi+2∑i=1nsi∗(si−1)−2∑i=2nsi∗si(这里不包含根节点)
化简一下即为 n2n^{2}n2级别!