動態規划題目整理


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就是前輩給后輩做出貢獻的東西,后輩只能從前輩那里"學到東西"


免責聲明!

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



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