下面是兩道例題:
設當前父節點爲x,其子節點爲y1,y2,...,yn
《沒有上司的舞y2會》:每條邊上最多選擇一個點,求最大權值
狀態轉移方程:
f[x,0]=max(f[y1,0],f[y1,1])+max(f[y2,0],f[y2,1])+...+max(f[yn,0],f[yn,1])
f[x,1]=f[y1,0]+f[y2,0]+...+f[yn,0]
《戰略遊戲》:每條邊上最少選擇一個點,求最小權值
狀態轉移方程:
f[x,0]=f[y1,1]+f[y2,1]+...+f[yn,1]
f[x,1]=min(f[y1,0]+f[y1,1])+min(f[y2,0],f[y2,1])+...+min(f[yn,0],f[yn,1])
Ural大學有N名職員,編號爲1~N。
他們的關係就像一棵以校長爲根的樹,父節點就是子節點的直接上司。
每個職員有一個快樂指數,用整數 Hi 給出,其中 1≤i≤N。
現在要召開一場週年慶宴會,不過,沒有職員願意和直接上司一起參會。
在滿足這個條件的前提下,主辦方希望邀請一部分職員參會,使得所有參會職員的快樂指數總和最大,求這個最大值。
輸入格式
第一行一個整數N。
接下來N行,第 i 行表示 i 號職員的快樂指數Hi。
接下來N-1行,每行輸入一對整數L, K,表示K是L的直接上司。
輸出格式
輸出最大的快樂指數。
數據範圍
1≤N≤6000,
−128≤Hi≤127
輸入樣例:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
輸出樣例:
5
#include <iostream>
#include <vector>
using namespace std;
const int N = 6000+10;
vector<int>son[N];
int have[N],H[N],f[N][2];
void dp(int x){
f[x][0]=0;
f[x][1]=H[x];
for(int i=0;i<son[x].size();i++){
int y=son[x][i];
dp(y);
f[x][0]+=max(f[y][0],f[y][1]);
f[x][1]+=f[y][0];
}
}
int main(){
int n,root=1;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&H[i]);
}
for(int i=0;i<n-1;i++){
int x,y;
scanf("%d%d",&x,&y);
son[y].push_back(x);
have[x]=1;
}
while(have[root]) root++;
dp(root);
printf("%d",max(f[root][0],f[root][1]));
return 0;
}
鮑勃喜歡玩電腦遊戲,特別是戰略遊戲,但有時他找不到解決問題的方法,這讓他很傷心。
現在他有以下問題。
他必須保護一座中世紀城市,這條城市的道路構成了一棵樹。
每個節點上的士兵可以觀察到所有和這個點相連的邊。
他必須在節點上放置最少數量的士兵,以便他們可以觀察到所有的邊。
你能幫助他嗎?
例如,下面的樹:
只需要放置1名士兵(在節點1處),就可觀察到所有的邊。
輸入格式
輸入包含多組測試數據,每組測試數據用以描述一棵樹。
對於每組測試數據,第一行包含整數N,表示樹的節點數目。
接下來N行,每行按如下方法描述一個節點。
節點編號:(子節點數目) 子節點 子節點 …
節點編號從0到N-1,每個節點的子節點數量均不超過10,每個邊在輸入數據中只出現一次。
輸出格式
對於每組測試數據,輸出一個佔據一行的結果,表示最少需要的士兵數。
數據範圍
0<N≤1500
輸入樣例:
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
輸出樣例:
1
2
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1500+10;
int head[N],nexts[N*2],ver[N*2];
int have[N],f[N][2];
int tot;
void add(int x,int y){
ver[++tot]=y;
nexts[tot]=head[x],head[x]=tot;
}
void dp(int x){
f[x][0]=0;
f[x][1]=1;
for(int i=head[x];i;i=nexts[i]){
int y=ver[i];
dp(y);
f[x][0]+=f[y][1];
f[x][1]+=min(f[y][0],f[y][1]);
}
}
int main(){
//freopen("1.txt","r",stdin);
int n;
while(~scanf("%d",&n)){
memset(have,0,sizeof(have));
memset(head,0,sizeof(head));
tot=0;
int x,m,y,root=0;
for(int i=0;i<n;i++){
scanf("%d:(%d)",&x,&m);
while(m--){
scanf("%d",&y);
add(x,y);
have[y]=1;
}
}
while(have[root]==1) root++;
dp(root);
printf("%d\n",min(f[root][0],f[root][1]));
}
return 0;
}