树上取数

来源:互联网 发布:淘宝网什么时候搞活动 编辑:程序博客网 时间:2024/05/18 01:37

在树上取n个点,使得权值和最大,并且要满足条件:如果某棵子树两棵或以上的子树有点选中,那么该子树的根也必须选中。

树形动态规划。

max[i][j][k]代表以i为根的子树选或不选i,最多能选k个点最大收益。

#include<cstdio>#include<cstring>#include<string.h>#include<iostream>#include<math.h>#include<vector>using namespace std;int map[110][110],fa[110],degree[110],maxn[110][2][110],num[110];int n,m;void init(){int i,x,y;memset(map,0,sizeof(map));scanf("%d%d",&n,&m);if(m>n)m=n;for(i=1;i<=n;i++)scanf("%d",&num[i]);for(i=1;i<n;i++){scanf("%d%d",&x,&y);map[x][y]=1;map[y][x]=1;}}void creat_tree(){int mark[110],stack[110];int i,j,total;memset(mark,0,sizeof(mark));memset(degree,0,sizeof(degree));stack[1]=1;mark[1]=1;fa[1]=0;i=total=1;while(i<=total){for(j=1;j<=n;j++)if(!mark[j]&&map[stack[i]][j]){fa[j]=stack[i];degree[stack[i]]++;mark[j]=1;stack[++total]=j;}i++;}}void work(){int i,j,k;creat_tree();memset(maxn,0,sizeof(maxn));for(i=1;i<=n;i++){maxn[i][0][0]=0;maxn[i][1][1]=num[i];}while(1){for(i=1;i<=n;i++)if(degree[i]==0)break;if(i>n)break;for(j=0;j<=1;j++)for(k=1;k<=m;k++)if(maxn[i][j][k]>maxn[fa[i]][0][k])maxn[fa[i]][0][k]=maxn[i][j][k];for(k=m;k>=m;k--)if(maxn[fa[i]][1][k]>=0)for(j=1;j<=m-k;j++){if(maxn[i][0][j]>=0&&maxn[i][0][j]+maxn[fa[i]][1][k]>maxn[fa[i]][1][k+j])maxn[fa[i]][1][k+j]=maxn[i][0][j]+maxn[fa[i]][1][k];if(maxn[i][1][j]>=0&&maxn[i][1][j]+maxn[fa[i]][1][k]>maxn[fa[i]][1][k+j])maxn[fa[i]][1][k+j]=maxn[i][1][j]+maxn[fa[i]][1][k];}degree[fa[i]]--;degree[i]=-1;}if(maxn[1][0][m]>maxn[1][1][m])printf("%d\n",maxn[1][0][m]);else printf("%d\n",maxn[1][1][m]);}int main(){init();work();return 0;}


原创粉丝点击