洛谷P1352没有上司的舞会+树形二维DP
题意:上司和直接下属,不能同时去一个聚会,问可邀请到的人的快乐值最大是多少;
参考:https://www.luogu.org/blog/mak2333/solution-p1352
思路:
首先我们们分析一下这道题,对于每一个人,它所做的决定对上司和下属都有影响,我们可以只看一方,也就是上司对下属的影响,因为这样的影响是相互的。
状态如果为f[i]表示第i个人的位置能获得最大的幸福行吗?
由于我们的选择具有后效性,因为你去或不去对下属有影响,那显然不行。遇到这种情况我们该怎么办?
加一维
由于后效性实质上是我们对于状态的性质不够清楚,所以我们再加一维以实现就算你加还是不加我们都可以记录下来。所以状态其实是很好想的。想出状态后,容易推出方程为
dp[i][0]+=sum(max(dp[son][1],dp[son][0])); //显然,你不去,那下属就可以想去就去。
dp[i][1]=sum(dp[son][0])+happy[i]; //显然你去了那下属就一定不能去。
由此我们就可以愉快的DFS了。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <vector> #include <map> #include <set> #include <queue> #include <list> #include <iterator> #include <cmath> using namespace std; #define lson (l , mid , rt << 1) #define rson (mid + 1 , r , rt << 1 | 1) #define debug(x) cerr << #x << " = " << x << "\n"; #define pb push_back #define pq priority_queue #define Pll pair<ll,ll> #define Pii pair<int,int> #define fi first #define se second #define OKC ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define FT(A,B,C) for(int A=B;A <= C;++A) //用来压行 typedef long long ll; typedef unsigned long long ull; /*-----------------show time----------------*/ const int maxn = 6009; vector<int >mp[maxn]; int n; int hp[maxn],dp[maxn][2],fa[maxn]; void dfs(int u,int o) { for(int i=0; i<mp[u].size(); i++) { int tmp = mp[u][i]; if(tmp==o)continue; dfs(tmp,u); dp[u][1] = max(dp[tmp][0]+dp[u][1],dp[u][1]); dp[u][0] += max(dp[tmp][1],dp[tmp][0]); } dp[u][1] += hp[u]; } int main(){ scanf("%d", &n); for(int i = 1; i<=n; i++)scanf("%d" , hp+i),fa[i] = i; for(int i =1; i<=n; i++) { int u,v; scanf("%d%d", &u, & v); if(u+v==0)break; mp[v].pb(u); fa[u] = v; } int s = n; while(s!=fa[s]) { s = fa[s]; } dfs(s,-1); printf("%d\n",max(dp[s][1],dp[s][0])); return 0; }
参考中还提到,如果人数过多,或者是一条链的时候,可以用BFS+队列,拓扑排序优化。我感觉主要思路,就是把从子节点到父节点的路径找出来
skr