树形dp ural1018苹果二叉树
来源:互联网 发布:优化手机相机 编辑:程序博客网 时间:2024/05/22 18:56
#include<iostream>#include<vector>#include<string>#include<queue>#include<cstdio>#include<cstring>#define maxn 200#define INF 0xfffffffusing namespace std;int dp[maxn][maxn];//dp[i][j]表示以i为根取j条树枝的最大值//1.只有一个子树//dp[i][j]=max(dp[child][j-1]+val[i][child]);//2.有两个子树//dp[i][j]=max(dp[child1][k]+dp[child2][j-k-2]) 0<=k<=j-2;//这里采用记忆化搜索,记录所有可能的状态,因为点还是比较少的。//一般的树形dp是先求出子树的状态,再根据子树的状态去得出根的状态,这有明显的层次结构的。int n,m;vector<int> g[maxn];//因为要判断每棵树的子树个数,所以用vector比较好用int map[maxn][maxn],vis[maxn];void init(){ for(int i=1; i<=n; i++) { g[i].clear(); } memset(vis,0,sizeof(vis)); memset(dp,0,sizeof(dp)); memset(map,0,sizeof(dp));}int dfs(int u,int q,int f){ vis[u]=1; int size=g[u].size(); if(size==0||q<=0||(size==1&&f!=-1))//只有一个点,不可以摘,叶子节点 { return 0; //叶子节点或者不能摘结束 } if(dp[u][q]!=0) return dp[u][q]; //cout<<u<<' '<<v[1]<<' '<<v[2]<<' '; //int v1=g[u][0],v2=g[u][1]; /* 2 2 1 2 10 */ if((g[u].size()==2&&f!=-1)||(g[u].size()==1&&f==-1)) { //cout<<"yes"<<endl; int v=g[u][0]; if(v==f) v=g[u][1]; dp[u][q]=max(dp[u][q],dfs(v,q-1,u)+map[u][v]);//只有一棵子树 //cout<<u<<' '<<q<<' '<<dp[u][q]<<endl; } else { int v[5],cnt=0; for(int i=0; i<size; i++) //找出子树结点 { if(g[u][i]!=f) { v[++cnt]=g[u][i]; } } dp[u][q]=max(dp[u][q],dfs(v[1],q-1,u)+map[u][v[1]]);//只取第一棵子树 //cout<<dfs(v[1],q-1)+map[u][v[1]]<<' '; dp[u][q]=max(dp[u][q],dfs(v[2],q-1,u)+map[u][v[2]]);//只取第二棵子树 //cout<<dfs(v[2],q-1)+map[u][v[2]]<<endl; for(int k=0; k<q-1; k++) //两棵树的边都取 { dp[u][q]=max(dp[u][q],dfs(v[1],k,u)+map[u][v[1]]+dfs(v[2],q-k-2,u)+map[u][v[2]]); } } //cout<<dp[u][q]<<endl; return dp[u][q];}int main(){ int u,v,val,i,j,k; while(cin>>n>>m) { init(); for(int i=1; i<n; i++) { cin>>u>>v>>val; g[u].push_back(v); g[v].push_back(u); map[u][v]=val; map[v][u]=val; } dfs(1,m,-1); cout<<dp[1][m]<<endl; } return 0;}