动态规划题目整理

dp题目整理

背包问题

榨取kkksc03

因为题目中有两个限制条件,所以并不能当做一般背包问题来做,

既然限制条件(类似于"体积")多了一个,那么现在维数也多开一维,同时表示其状态

我们又发现,这个题每种物品(需求)只能取一次,所以这是一道多维0/1背包题目

那么这题就很好做了

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,t;
int dp[205][205];
int mi[105];
int ti[105];
int main(){
	scanf("%d%d%d",&n,&m,&t);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&mi[i],&ti[i]);
	for(int i=1;i<=n;i++)
		for(int j=t;j>=ti[i];j--)
			for(int k=m;k>=mi[i];k--)
				dp[j][k]=max(dp[j-ti[i]][k-mi[i]]+1,dp[j][k]);
	printf("%d",dp[m][t]);
	return 0;
}

求概率等的题目则更像是数学题,更需要好好分析其中的条件分析式子以推出状态转移方程

搞笑世界杯

显然,暴力枚举是不行的,那么现在考虑如何表示状态

\(dp[i][j]\)表示A种票,B种票分别售出\(i\)张,\(j\)张时两人票相同的概率

首先考虑边界条件,

如果某一种票已经发完了,那么其概率一定是1,

就有:\(dp[i][0]=dp[0][i]=1\)

然后再考虑转移方程

对于当前的人,要么发到A种,要么B种,这样一来,其状态就都能够从前面状态转移而来

也就是都能从\(dp[i-1][j]\)\(dp[i][j-1]\)转移而来

就是这样:

\(dp[i][j]=(dp[i-1][j]+dp[i][j-1])/2\)

这里除以2的原因是两种情况各占一种,其概率要平均分

初始化和状态转移分析完了,剩下就只是数据处理部分了

然后代码长这样:

#include<iostream>
#include<cstdio>
using namespace std;
int n;
double dp[1255][1255];
int main(){
	scanf("%d",&n);
	n/=2;
	for(int i=2;i<=n;i++)
		dp[i][0]=dp[0][i]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			dp[i][j]=(dp[i-1][j]+dp[i][j-1])/2.0;
	printf("%0.4lf\n",dp[n][n]);
	return 0;
}

代码同样很短,这就是dp的魅力所在,用极小的篇幅带来不小的思维量

总之记住一点,dp就是前辈给后辈做出贡献的东西,后辈只能从前辈那里"学到东西"

posted @ 2020-06-21 08:47  _Alex_Mercer  阅读(251)  评论(0编辑  收藏  举报