poj1155(树形dp+背包)
src:http://poj.org/problem?id=1155
思路:dp[u][i]指子树u取i个叶子的最优值,Max(dp[u][i],dp[u][i-k]+dp[v][k]-edge[i].v),注意是从前几个阶段转移后的最优值中选(例codeforces219D(树形dp) ,dp[u][i]指节点依赖于i子节点),还是前几个阶段转移过来的共同构成(如此题,dp[u][i]表示结点u取i个前面的阶段)。
此题思路是首先知道回到根节点dp【u】【i】最多挑选几个叶子节点, 那我们就可以确定子问题就是dp【v】【】是在子节点v是最多挑选几个叶节点
ac代码:
#include <iostream> #include<cstdlib> #include<algorithm> #include<cmath> #include<functional> #include<utility> #include<string> #include<string.h> #include<vector> #include<iomanip> #include<stack> using namespace std; #define FOR(i,a,b) for(int i=a;i<=b;i++) #define Max(a,b) a=max(a,b) #define Min(a,b) a=min(a,b) const int inf=99999999; int n,m,dp[3001][3001],head[3001],Enum=0,val[3001],sz[3001]; struct node { int to,v,ne; }edge[3005]; void add_edge(int a,int b,int v){edge[Enum].to=b;edge[Enum].v=v;edge[Enum].ne=head[a];head[a]=Enum++;} void init() { memset(head,-1,sizeof(head)); memset(sz,0,sizeof(sz)); } void dfs1(int u)//确定各节点的背包大小(可选的叶子节点数量) { if(u>n-m){sz[u]=1;return;} for(int i=head[u];i!=-1;i=edge[i].ne){ int v=edge[i].to; dfs1(v); sz[u]+=sz[v]; } FOR(i,1,sz[u])dp[u][i]=-inf; } void dfs2(int u) { if(u>n-m){ dp[u][1]=val[u];return; } for(int i=head[u];i!=-1;i=edge[i].ne){ int v=edge[i].to; dfs2(v); for(int j=sz[u];j>=1;j--)for(int k=1;k<=sz[v];k++)if(j>=k){ Max(dp[u][j],dp[u][j-k]+dp[v][k]-edge[i].v); } } } int main() { ios::sync_with_stdio(false); while(cin>>n>>m){ init(); int tt,b,v; for(int i=1;i<=n-m;i++){ cin>>tt; for(int j=1;j<=tt;j++){ cin>>b>>v; add_edge(i,b,v); } } dfs1(1); FOR(i,n-m+1,n)cin>>val[i]; dfs2(1); int ans=0; for(int i=sz[1];i>=1;i--)if(dp[1][i]>=0){ans=i;break;} cout<<ans<<endl; } return 0; }

浙公网安备 33010602011771号