1. 程式人生 > >P1472 奶牛家譜 Cow Pedigrees

P1472 奶牛家譜 Cow Pedigrees

太精妙,留著以後慢慢消化

https://www.luogu.org/problemnew/show/P1472

法一:

我們一層一層地來推,列舉層數,然後再列舉這一層選擇的奶牛的個數(必須是偶數個的,因為我第一層已經處理好了),然後再列舉上一層選擇的奶牛的個數(也必須是偶數的,因為我把第二層也特殊處理了,就可以從第三層開始了),但是發現一共要選擇n個奶牛,所以不得不再加一維目前總共選擇的奶牛的數量,也就是加一層迴圈來列舉v罷了;現在就是重點!!!假設上一層選擇了m只奶牛,這一層選擇了j只奶牛,那麼m必須滿足m>=j/2(因為二叉樹的性質),假設上一層的狀態為f[i-1][m][v-j],也就是i-1層選擇了m只奶牛,前i-1層總共選擇了v-j只奶牛的方案總數,這時第i層就是選擇了j只奶牛了,第i層的j只奶牛和第i-1層的m只奶牛互相找媽媽,那麼可以選擇的方案總數就是C(m,j/2)*f[i-1][m][v-j],最後再統計就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll ,ll > P;
#define INF 0xf3f3f3f
const int Max=int(1000+10);
const int mol=9901;
int n,k,dp[100+10][200+10][200+10],w[200+10][200+10];
int main() {
	while(~scanf("%d%d",&n,&k)) {
		w[0][0]=1;	    
		dp[1][1][1]=1;
		dp[2][2][3]=1;
		for(int i=1;i<=n;i++)
		   for(int j=0;j<=i;j++)
		      if(j==0||i==j) 
		        w[i][j]=1;
		       else
			    w[i][j]=(w[i-1][j]+w[i-1][j-1])%mol;
		
		for(int i=3;i<=k;i++)
		   for(int j=2;j<=(n/2+1);j+=2)
		      for(int x=j+1;x<=n;x++)
			      for(int y=j/2;y<=n/2+1;y++)	
				      if(y%2==0)
				        dp[i][j][x]+=w[y][j/2]*dp[i-1][y][x-j]%mol;
		ll ans=0;
		for(int i=1;i<=n;i++)
		  ans+=dp[k][i][n];
		printf("%lld\n",ans%mol);  			  	 
	}            

	return 0;
}

法二:

採用記憶化搜尋來解決這道題。

我們規定左子樹必須正好滿足要求,即左子樹高度為y-1,而右子樹高度小於等於y-1(如果左右子樹高度不等,則左右子樹可以互換,方案乘以2)然後我們用兩個for迴圈分別列舉左子樹的節點數與右子樹的高度值(小於等於y-1),利用乘法原理狀態轉移。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll ,ll > P;
#define INF 0xf3f3f3f
const int Max=int(1000+10);
#define MOD 9901
bool bVis[212][112];
int dp[212][112];
int n, m;
int dfs(int cnt, int height)
{
    if (bVis[cnt][height]) return dp[cnt][height];
    if (cnt == 1) return height == 1;
    bVis[cnt][height] = true;
    if (height > (cnt + 1) / 2) return 0;
    if (height <= 1) return 0;
    int& state(dp[cnt][height]);
    for (int i(1); i < cnt; i += 2)
    {
        for (int j(1); j < height; ++j)
        {
            state += dfs(i, height - 1) * dfs(cnt - i - 1, j);
            state %= MOD;
            if (height - 1 != j)//如果高度相等,那麼互換反而會導致方案重複(不妨試著模擬一下或者輸出引數)
            {
                state += dfs(i, height - 1) * dfs(cnt - i - 1, j);
                state %= MOD;
            }
        }
    }
    return state;
}

int main()
{
    scanf("%d%d", &n, &m);
    printf("%d\n", dfs(n, m));
    return 0;
}