1. 程式人生 > >洛谷P1352沒有上司的舞會+樹形二維DP

洛谷P1352沒有上司的舞會+樹形二維DP

CA TE eve list stream sig fine -s esp

傳送門

題意:上司和直接下屬,不能同時去一個聚會,問可邀請到的人的快樂值最大是多少;

參考: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; }
DFS

參考中還提到,如果人數過多,或者是一條鏈的時候,可以用BFS+隊列,拓撲排序優化。我感覺主要思路,就是把從子節點到父節點的路徑找出來

洛谷P1352沒有上司的舞會+樹形二維DP