(樹形dp入門)
阿新 • • 發佈:2018-12-20
題目一:Anniversary party
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1520
題意:有n個客人,每個客人有一個開心值,然後客人K是客人L的主管,客人K和客人L不能一起被邀請參加party,問:邀請人的最大開心值是多少?
題解:顯然這是道樹形dp 的題,我們定義 dp[i][1]表示邀請客人i,dp[i][0]表示不邀請客人i,
故轉移方程為:
dp[i][1]+=d[j][0] ,
dp[i][0]+=max(dp[j][1],dp[j][0])。
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int maxn=6010; int dp[maxn][2]; vector<int> G[maxn]; int fa[maxn]; int dfs(int root) { int len=G[root].size(); for(int i=0;i<len;i++) ///一直遞迴到葉子節點,返回上一層開始 dfs(G[root][i]); for(int i=0;i<len;i++) { dp[root][1]+=dp[G[root][i]][0]; dp[root][0]+=max(dp[G[root][i]][0],dp[G[root][i]][1]); } } int main() { int n; while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) { scanf("%d",&dp[i][1]); ///表示邀請客人i的開心值 dp[i][0]=0; G[i].clear(); fa[i]=-1; } int L,K; while(scanf("%d%d",&L,&K)) { if(L==0&&K==0) break; ///在這裡我們就不建立雙向邊了,因為我們是從最深一層開始往上dp,故每個節點都會只搜一次 G[K].push_back(L); fa[L]=K; /// } int root=1; ///找到根節點 while(fa[root]!=-1) root=fa[root]; dfs(root); printf("%d\n",max(dp[root][1],dp[root][0])); } return 0; }
題目二:Strategic Game
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=1054
題意:給你一個n個節點的樹,讓你挑選出一些節點放士兵,使得所有邊都能被士兵監視,讓你儘可能的少放士兵。
題解:
顯然這道題跟上一道類似,也可以用樹形dp來解決,還是一樣dp[i][1]表示挑選節點i放士兵,dp[i][0]表示不挑選節點i放士兵,
轉移方程為:
dp[i][0]+=d[j][1] ,
dp[i][1]+=min(dp[j][1],dp[j][0])。
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int maxn=1510; int dp[maxn][2]; vector<int> G[maxn]; int fa[maxn]; int dfs(int root) { // printf("f"); int len=G[root].size(); for(int i=0;i<len;i++) ///一直遞迴到葉子節點,返回上一層開始 dfs(G[root][i]); for(int i=0;i<len;i++) { dp[root][0]+=dp[G[root][i]][1]; dp[root][1]+=min(dp[G[root][i]][0],dp[G[root][i]][1]); } } int main() { int n; while(~scanf("%d",&n)) { for(int i=0;i<n;i++) { dp[i][1]=1;///表示邀請客人i的開心值 dp[i][0]=0; G[i].clear(); fa[i]=-1; } int root,rootlen,son; for(int i=0;i<n;i++) { scanf("%d:(%d)",&root,&rootlen); while(rootlen--){ scanf("%d",&son); ///在這裡我們就不建立雙向邊了,因為我們是從最深一層開始往上dp,故每個節點都會只搜一次 G[root].push_back(son); fa[son]=root; } } root=0; ///找到根節點 while(fa[root]!=-1) root=fa[root]; // printf("f"); dfs(root); printf("%d\n",min(dp[root][1],dp[root][0])); } return 0; }