hiho1055 - 樹形dp轉換成背包
阿新 • • 發佈:2017-05-13
get urn pro clas 一個 函數計算 val names include
題目鏈接
輸入:一棵樹,每個節點一個權值。
輸出:包括1號節點在內的m個節點組成的連通分量的權值和的最大值
/**********************************************/
計 dp(i,j) 為以i為根的子樹選中j個點(包括i)時的最大權值和。則dp(1,m)即為所求。
方程:
{
dp[i][0] = 0;
dp[i][1] = value[i];
foreach child c of i
for j = m...2
for k = 1...j-1
dp[i][j] = max(dp[i][j],dp[i][j-k]+dp[c][k])
}
因為dp的核心就是記憶化搜索,所以自下向上遍歷整棵樹,處理完一個節點就標記一下,下次用到這個節點的時候就不用再遞歸了。
這裏我用getCnt()函數計算了一下以每個節點i為根的子樹中節點的數目cnt(i),為的是縮小求dp(i,j)中j和k的上限,由m變為MIN(m,cnt(i)),應該不會提速多少
#include <set> #include <map> #include <stack> #include <queue> #include <cmath> #include <vector> #include <string> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define MAX(a,b) ((a)>=(b)?(a):(b)) #define MIN(a,b) ((a)<=(b)?(a):(b)) #define long long LL #define OO 0x0fffffff using namespace std; const int N = 111; struct Edge{ int to; int next; }; int eid = 0; Edge edges[N*2]; int heads[N]; void addEdge(int a,int b){ edges[eid].to = a; edges[eid].next = heads[b]; heads[b] = eid++; edges[eid].to = b; edges[eid].next = heads[a]; heads[a] = eid++; } int m,n; int dp[N][N],cnt[N],visited[N]; void getCnt(int id){ visited[id] = 1; for(int cur = heads[id];cur!=-1;cur=edges[cur].next){ int cid = edges[cur].to; if(!visited[cid]) { if(!cnt[cid]) getCnt(cid); cnt[id] += cnt[cid]; } } cnt[id] += 1; } void traverse(int id){ visited[id] = 1; for(int cur=heads[id];cur!=-1;cur=edges[cur].next){ int cid = edges[cur].to; if(!visited[cid]){ if(visited[cid]!=2) traverse(cid); for(int i=MIN(m,cnt[id]);i>=2;i--){ for(int j=1;j<MIN(i,cnt[cid]+1);j++){ dp[id][i]=MAX(dp[id][i],(dp[id][i-j]+dp[cid][j])); } } } } visited[id] = 2; } int main(){ scanf("%d%d",&n,&m); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) scanf("%d",dp[i]+1); int a,b; memset(heads,-1,sizeof(heads)); for(int i=0;i<n-1;i++){ scanf("%d%d",&a,&b); addEdge(a,b); } memset(cnt,0,sizeof(cnt)); memset(visited,0,sizeof(visited)); getCnt(1); memset(visited,0,sizeof(visited)); traverse(1); printf("%d\n",dp[1][m]); return 0; }
hiho1055 - 樹形dp轉換成背包