电子学会四级-动态规划

技能树
sum i j 高度小于等于i 节点数为j的二叉树个数

sum i-1 j 高度小于等于i-1 节点数为j的二叉树个数

dp i j 高度等于i 节点数为j的二叉树个数

sum i j = sum i-1 j + dp i j

右子树不同二叉树个数

sum i-1 j-1-k

左子树和右子树分别完成种类数的一部分,所以使用乘法原理得到总的种类数

此时,这课原来高度为i,节点数为j的树包含二叉树个数为 dp i-1 k * sum i-1 j-1-k

同理,右子树也可以是高度为i-1的子树,那么总的二叉树个数也前面左子树高度为i-1相同,总二叉树个数为

(dp i-1 k * sum i-1 j-1-k) * 2

注意 有一种情况在左右子树分别计算时,被算了两次,即:左右子树高都为i-1时,这种情况二叉树个数为

dp i-1 k * dp i-1 j-k-1 j总节点数-k左子树接点数-1 根节点

#include<bits/stdc++.h>
using namespace std;
#define N 310
#define M 110
#define mod 9901
int f[M][N],sum[N][M];
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	f[1][1]=sum[1][1]=1;
	for (int j=2; j<=n; j++)
		f[1][j]=sum[1][j]=0;
	for (int i=2; i<=m; i++){
		for (int j=1; j<=n; j++){
			f[i][j]=0;
			for (int k=1; k<j; k++)
				f[i][j]=(f[i][j]+(2*f[i-1][k]*sum[i-1][j-k-1]-f[i-1][k]*f[i-1][j-k-1])%mod)%mod;
			sum[i][j]=(sum[i-1][j]+f[i][j])%mod;
		}
	}
	printf("%d\n",f[m][n]);
	return 0;
}

2000 最长公共子上升序列

题解

dp[j]表示a取到1 .. i,b取到1 .. j,且以b[j]结尾的最长公共上升子序列

a[i]==b[j]时,需要取前面比b[j]小的最长公共上升子序列+1

比如:

2 6

2 6

dp[1]=1两个2是第一个最长公共上升子序列

黑色的6相等,所以为dp[1]+1=2

a[i]>b[j]时,存储maxdp=max(dp[j]) 即为a取1 .. i-1,b取1 .. j的最长公共上升子序列

例如

2 6

2 6

a取到1 .. 2,b取1时,dp[1]=1 maxdp=1,为a取到1 .. 2,b取1 .. 2时,数据赋值做准备

a[i]<b[j]不对最长公共上升子序列做贡献

例如

7 6

7 6

黑色字体6<7 虽然dp[1]=1,并且6 6是相同 并不是上升的,因此不应该在dp[1]基础上累加本次相同的6

#include<bits/stdc++.h>
using namespace std;
 
int a[505],b[505];
 
struct node{
	vector<int> v;
	int val=0;//初始化
}dp[505];//a取1~i b取1~j且以b[j]结尾的最长公共上升子序列 
 
int main(){
	int n,m;
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i];
	}
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>b[i];
	}
	
	for(int i=1;i<=m;i++){
		//a取1~i b取1~j且以b[j]结尾的最长公共上升子序列 
		node maxn; 
		for(int j=1;j<=n;j++){
			//1.a[i]>b[j]时maxn 找比a[i]小且以b[j]结尾的最长公共上升子序列
			//2.其中1中最长公共上升子序列为a取1~i-1 b取1~j-1 时组成的 
			//3.为a[i]==b[j]时为dp[j]赋值做准备 
			if(a[i]>b[j]&&maxn.val<dp[j].val){
				maxn=dp[j];
			}
			//必须相等才可能组成公共子序列 
			if(a[i]==b[j]){
				//相等时长度在之前最长基础加1 
				dp[j].val=maxn.val+1;
				//复制之前最长序列 
				dp[j].v=maxn.v;
				dp[j].v.push_back(b[j]); 
			}
		}
	}
	//循环取出dp[].val最长的 
	node maxn=dp[1];
	for(int i=2;i<=n;i++){
		if(dp[i].val>maxn.val){
			maxn=dp[i];
		}
	}
	//输出最长值 
	cout << maxn.val <<endl;
	//输出最长序列 
	for(int i=0;i<maxn.v.size();i++){
		cout << maxn.v[i] << " ";
	}
	return 0;
}
posted @ 2022-03-13 10:09  new-code  阅读(30)  评论(0编辑  收藏  举报