樹形dp(以邊爲單位)

下面是兩道例題:

設當前父節點爲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;
}

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章