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;
}

猜你喜欢

转载自blog.csdn.net/PinkAir/article/details/81582959