NKOJ 1791 Party at Hali-Bula(树状DP)
題目大意是某些人將去參加一次party 但是他們和他們不能和他們的上司一起參加,問滿足此條件的情況下能去的最多人數
首先由給出的條件建好樹,我是用鄰接矩陣來存的,主要是為了方便,實際上效率還是比較低的。
需要保存兩個狀態 一是某節點不用(即此人不去的情況)時該節點和該節點子樹的最大值dp[i][0];
?? ? ? ? ? ? ? ? ? ? ? 二是是用該節點時,該節點及其子樹的最大值dp[i][1];
?
對于dp[i][1] 狀態轉移方程比較明顯 dp[i][1]=1+∑(dp[j][0])j是i的“孩子”;因為 i 去,則他的孩子就不能去了,所以此種情況下,能去的最大人數就是在他所有孩子不去的情況下的最大人數加他自己了。
?
dp[i][0]:由于i不去,i的孩子j也可去可不去 此時狀態轉移方程為: dp[i][0]=∑(max(dp[i][0],dp[i][1]))
?
還需判斷去的人數最多的情況,這些人是不是固定的。
?
對于葉子節點 pan[j][0]=1;pan[j][1]=1;表示人數是確定的。
?
對于任意節點i dp[i][1] 固定即pan[i][1]=1當且僅當 i 的所有孩子 j pan[j][0]=1;
?
dp[i][0] :
對于任意一個孩子 j 如果有 dp[ij[0]>dp[j][1]&&pan[j][0]==0或者 dp[j][0]<dp[j][1]&&pan[j][1]==0 或者dp[j][0]==dp[j][1]
?? ? ? ? ? ? ? ? pan[i][0]=0;
?
即,構成dp[i][0]的數據中,如果有一個是不確定的,那么dp[i][0]就是不確定的
?
我用的是記憶化搜索來實現DP的
代碼:
?
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <stdio.h>
#include <map>
#include <algorithm>
using namespace std;
?
int n;
bool rela[210][210];
bool pan[210][2];
int dp[210][2];
?
int main()
{
?? ?while (cin>>n&&n)
?? ?{
?? ? ? ?memset(rela,0,sizeof(rela));
?? ? ? ?memset(pan,1,sizeof(pan));
?
?? ? for(int i=0;i<=n;++i){
?
?? ? ? ? dp[i][0]=dp[i][1]=-1;
?? ? ? ? }
?
?? ? ? ?map<string,int> myMap;
?? ? ? ?int i(1);
?? ? ? ?string a,b;
?? ? ? ?cin>>a;
?? ? ? ?myMap[a]=i;
?? ? ? ?int j(1);
?? ? ? ?while (j<n)
?? ? ? ?{
?? ? ? ? ? ?cin>>a;
?? ? ? ? ? ?cin>>b;
?? ? ? ? ? ?if (!myMap.count(a)) myMap[a]=++i;
?? ? ? ? ? ?if (!myMap.count(b)) myMap[b]=++i;
?
?? ? ? ? ? ?rela[myMap[b]][myMap[a]]=1;
?
?? ? ? ? ? ?++j;
?? ? ? ?}
/*
?? ? ? ?j=1;
?? ? ? ?while(j<=n){
?
?? ? ? ? ? ?int k(1);
?? ? ? ? ? ?while(k<=n){
?? ? ? ? ? ? ? ?cout<<rela[j][k]<<" ";
?? ? ? ? ? ? ? ?++k;
?? ? ? ? ? ? ? ?}
?? ? ? ? ? ?cout<<endl;
?? ? ? ? ? ?++j;
?? ? ? ? ? ?}
*/
?? ? ? ?void dfs(int n);
?? ? ? ?j=1;
?? ? ? ?while (j<=n)
?? ? ? ?{
?? ? ? ? ? ?dfs(j);
?? ? ? ? ? ?++j;
?? ? ? ?}
?
?? ? ? ?bool mul(0);
?? ? ? ?int maxOut=max(dp[1][1],dp[1][0]);
?? ? ? ?if(dp[1][1]>dp[1][0]&&!pan[1][1]) mul=1;
?? ? ? ?if(dp[1][1]<dp[1][0]&&!pan[1][0]) mul=1;
?? ? ? ?if(dp[1][1]==dp[1][0]) mul=1;
?
?
?? ? ? ?cout<<maxOut<<" ";
?? ? ? ?if (mul) cout<<"No"<<endl;
?? ? ? ?else cout<<"Yes"<<endl;
?? ?}
?
?? ?return 0;
}
?
void dfs(int num)
{
?
?
?? ?int j(1);
?? ?int tempA(0);
?? ?bool mulA(0);
?? ?int tempB(0);
?? ?bool mulB(0);
?? ?bool isLeaf(1);
?? ?while (j<=n)
?? ?{
?? ? ? ?if (rela[num][j])
?? ? ? ?{
?? ? ? ? ? ?isLeaf=0;
?
?? ? ? ? ? ?if (dp[j][0]==-1)
?? ? ? ? ? ? ? ?dfs(j);
?
?? ? ? ? ? ?if (!pan[j][0]) mulB=1;
?
?? ? ? ? ? ?tempA+=max(dp[j][1],dp[j][0]);
?? ? ? ? ? ?if ((dp[j][1]>dp[j][0]&&!pan[j][1])||(dp[j][1]<dp[j][0]&&!pan[j][0])||(dp[j][1]==dp[j][0]))
?? ? ? ? ? ? ? mulA=1;
?? ? ? ? ? ?tempB+=dp[j][0];
?
?? ? ? ?}
?
?? ? ? ?++j;
?? ?}
?? ?if (isLeaf)
?? ?{
?? ? ? ?dp[num][0]=0;
?? ? ? ?dp[num][1]=1;
?? ? ? ?return;
?? ?}
?
?? ?dp[num][0]=tempA;
?? ?dp[num][1]=tempB+1;
?
?
?? ?if (mulA) pan[num][0]=0;
?? ?if (mulB) pan[num][1]=0;
?? ?return;
}
總結
以上是生活随笔為你收集整理的NKOJ 1791 Party at Hali-Bula(树状DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ 2186 popular cow
- 下一篇: ACM输入输出--多组测试用例--C、C