树形背包。DP递推的思路很简单....
但是由于节点有15万个,先不论空间复杂度,这样开dp数组 dp[150000+10][300+10],如果初始化是memset(dp,-1,sizeof dp),则必然超时。
所以需要一个状态数剪枝。。。即记录这个节点最多组合的数量。
UVALive是不限制内存的,所以dp[150000+10][300+10] 能够AC,HDU 4169 限制了内存大小,需要优化空间复杂度。
内存优化之后的代码,HDU上C++能AC,G++依旧MLE。
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn=150000+10; struct Node { int val; int fa; queue<int *>Q; vector<int>f; }node[maxn]; int n,k,root; int cnt[maxn]; int ans; void init() { memset(cnt,0,sizeof cnt); for(int i=1;i<=n;i++) { while(!node[i].Q.empty()) node[i].Q.pop(); node[i].f.clear(); } } void read() { for(int i=1;i<=n;i++) { scanf("%d%d",&node[i].fa,&node[i].val); if(!node[i].fa) root=i; else node[node[i].fa].f.push_back(i); } } void dfs(int now) { if(!node[now].f.size()) { cnt[now]=1; int *p=new int[cnt[now]+2]; p[0]=0; p[1]=node[now].val; node[node[now].fa].Q.push(p); delete[] p; return; } for(int i=0;i<node[now].f.size();i++) { int id=node[now].f[i]; cnt[now]=cnt[now]+cnt[id]; } cnt[now]=min(k,cnt[now]); int *p=new int[cnt[now]+2]; p[0]=0; for(int i=1;i<=cnt[now];i++) p[i]=-1; int id=0; while(!node[now].Q.empty()) { int *head=node[now].Q.front(); node[now].Q.pop(); for(int j=cnt[now];j>=0;j--) for(int s=0;s<=j&&s<=cnt[node[now].f[id]];s++) if(head[s]!=-1&&p[j-s]!=-1) p[j]=max(p[j],head[s]+p[j-s]); id++; } p[1]=max(p[1],node[now].val); node[node[now].fa].Q.push(p); if(now==1) { if(cnt[1]<k||p[k]==-1) ans=-1; else ans=p[k]; } delete[] p; return; } void work() { dfs(root); if(ans==-1) printf("impossible "); else printf("%d ",ans); } int main() { while(~scanf("%d%d",&n,&k)) { init(); read(); work(); } return 0; }
二维DP写法。HDU 上MLE的。UvaLive能过的。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n, k; int root; const int maxn = 150000 + 10; struct Edge { int now; int next; }e[maxn]; int head[maxn]; int cnt[maxn]; int val[maxn]; int dp[maxn][300 + 10]; int q; void init() { q=0; for(int i=1;i<=n;i++) head[i]=-1; } void read() { for (int i = 1; i <= n; i++) { int fa; scanf("%d%d", &fa, &val[i]); if (!fa) root = i; else { e[q].now=i, e[q].next=head[fa]; head[fa]=q, q=q+1; } } } void dfs(int now) { cnt[now]=0; if (head[now]==-1) { cnt[now]=1; dp[now][1] = val[now]; return; } for (int i = head[now]; i!=-1; i=e[i].next) { int id = e[i].now; dfs(id); cnt[now]=cnt[now]+cnt[id]; } cnt[now]=min(cnt[now],k); for(int i=0;i<=cnt[now];i++) dp[now][i]=-1; dp[now][0]=0; for (int i = head[now]; i!=-1; i=e[i].next) { int id = e[i].now; for(int j=cnt[now];j>=0;j--) for(int s=0;s<=j&&s<=cnt[id];s++) if(dp[id][s]!=-1&&dp[now][j-s]!=-1) dp[now][j]=max(dp[now][j],dp[id][s]+dp[now][j-s]); } dp[now][1]=max(val[now],dp[now][1]); } void work() { dfs(root); if (cnt[root]<k||dp[root][k] == -1) printf("impossible "); else printf("%d ", dp[root][k]); } int main() { while (~scanf("%d%d", &n, &k)) { init(); read(); work(); } return 0; }