613. 火车站饭店
政府邀请了你在火车站开饭店,但不允许同时在两个相连的火车站开。任意两个火车站有且只有一条路径,每个火车站最多有 50 个和它相连接的火车站。
告诉你每个火车站的利润,问你可以获得的最大利润为多少?
例如下图是火车站网络:
最佳投资方案是 1 , 2 , 5 , 6 这 4 个火车站开饭店可以获得的利润为 90.
那么,这是本蒟蒻做的第一道树形DP。
树形DP一般用搜索实现,先处理子节点,再处理自身,最终得到整棵树的最优解,总是默认1为根节点。
本题中用dp[i][0]表示不选i节点时的最大获利,dp[i][1]表示选择i节点时的最大获利。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
int G[maxn][51], value[maxn], dp[maxn][2], waynum[maxn];
bool vis[maxn][51];
int n;
void Init(){
scanf("%d",&n);
for(int i = 1; i <= n; i++)scanf("%d",&value[i]);
for(int i = 1; i <= n-1; i++){
int x,y;
scanf("%d%d",&x,&y);
G[x][waynum[x]++] = y;
G[y][waynum[y]++] = x;
}
}
void DP(int pos){
int temp(0), temp2(0);
for(int i = 0; i < waynum[pos]; i++){
if(!vis[pos][i]){
for(int j = 0; j < waynum[G[pos][i]]; j++){
if(G[G[pos][i]][j] == pos){
vis[G[pos][i]][j] = 1;//标记是否访问过
break;
}
}
DP(G[pos][i]);//与pos相连的某个节点(pos的儿子之一)
temp2 += dp[G[pos][i]][0];//不选以pos为根的子树
temp += max(dp[G[pos][i]][1],dp[G[pos][i]][0]);//在选与不选中取较大的
}
}
dp[pos][0] = temp;//不选pos节点
dp[pos][1] = temp2 + value[pos];//选pos节点
}
int main(){
#ifndef DEBUG
string FileName="profitz";
freopen((FileName+".in").c_str(),"r",stdin);
freopen((FileName+".out").c_str(),"w",stdout);
#endif
Init();
DP(1);
printf("%d",max(dp[1][0],dp[1][1]));
}