藍橋杯 - G將軍有一支訓練有素的軍隊 - [樹形DP]


G將軍有一支訓練有素的軍隊,這個軍隊除開G將軍外,每名士兵都有一個直接上級(可能是其他士兵,也可能是G將軍)。現在G將軍將接受一個特別的任務,需要派遣一部分士兵(至少一個)組成一個敢死隊,為了增加敢死隊隊員的獨立性,要求如果一名士兵在敢死隊中,他的直接上級不能在敢死隊中。
請問,G將軍有多少種派出敢死隊的方法。注意,G將軍也可以作為一個士兵進入敢死隊。
輸入格式
輸入的第一行包含一個整數n,表示包括G將軍在內的軍隊的人數。軍隊的士兵從1至n編號,G將軍編號為1。
接下來n-1個數,分別表示編號為2, 3, ..., n的士兵的直接上級編號,編號i的士兵的直接上級的編號小於i。
輸出格式
輸出一個整數,表示派出敢死隊的方案數。由於數目可能很大,你只需要輸出這個數除10007的余數即可。
樣例輸入1
3
1 1
樣例輸出1
4
樣例說明
這四種方式分別是:
1. 選1;
2. 選2;
3. 選3;
4. 選2, 3。
樣例輸入2
7
1 1 2 2 3 3
樣例輸出2
40

數據規模與約定
對於20%的數據,n ≤ 20;
對於40%的數據,n ≤ 100;
對於100%的數據,1 ≤ n ≤ 100000。


資源約定:
峰值內存消耗 < 256M
CPU消耗 < 2000ms


請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。

所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。

注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

提交時,注意選擇所期望的編譯器類型。

 

題解:

看一眼題目,不難想到是DFS,然后由於十分類似於樹形DP的經典入門題:http://www.cnblogs.com/dilthey/p/7152681.html

所以可以套用着做:

dp[i][0]:編號i者不去,(其子樹下)可以有多少種方案
dp[i][1]:編號i者去,(其子樹下)可以有多少種方案

我們可以先假設dp[i][0]包含編號為 i 的本人,以及其所有直接與間接下屬都不去的情況(即這一算一種方案);

那么所有葉子結點的dp[][0]=dp[][1]=1,(原本這里的dp[][0]應該等於0的);

然后我們有狀態轉移方程:

  dp[i][1] = dp[i_1][0] * dp[i_2][0] * dp[i_3][0] * …… * dp[i_K][0] 
  dp[i][0] = (dp[i_1][0]+dp[i_1][1]) * …… * (dp[i_K][0]+dp[i_K][1])  (i_k為i的第k個下屬,k = 1~K)

最后答案為:( dp[1][0] + dp[1][1] - 1 ) % 10007

即G將軍本人去和不去的2種情況下的方案和,去掉“G將軍和它的下屬全都不去”這種非法情況,再按題目要求模10007.

 

因為找不到OJ的地方所以AC不AC不太清楚的代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000+10;
const int MOD = 10007;

int dp[maxn][2];
//dp[i][0]:編號i者不去,(其子樹下)可以有多少種方案
//dp[i][1]:編號i者去,(其子樹下)可以有多少種方案
int n;

struct Edge{
    int u,v;
    Edge(int a,int b){u=a,v=b;};
};
vector<Edge> E;
vector<int> G[maxn];
void addedge(int par,int child)
{
    E.push_back(Edge(par,child));
    G[par].push_back(E.size()-1);
}
void init()
{
    E.clear();
    for(int i=0;i<maxn;i++) G[i].clear();
}

void dfs(int now)
{
    dp[now][0]=dp[now][1]=1;
    for(int i=0,nxt,_size=G[now].size();i<_size;i++)
    {
        nxt = E[G[now][i]].v;
        dfs(nxt);
        dp[now][1] = ( dp[now][1] * dp[nxt][0] )%MOD;
        dp[now][0] = ( dp[now][0] * (dp[nxt][0]+dp[nxt][1]) )%MOD;
    }
}

int main()
{
    init();

    scanf("%d",&n);
    for(int i=2,u;i<=n;i++)
    {
        scanf("%d",&u);
        addedge(u,i);
    }

    dfs(1);
    printf("%d\n",(dp[1][0]+dp[1][1]-1)%MOD);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM