dp題目整理
背包問題
因為題目中有兩個限制條件,所以並不能當做一般背包問題來做,
既然限制條件(類似於"體積")多了一個,那么現在維數也多開一維,同時表示其狀態
我們又發現,這個題每種物品(需求)只能取一次,所以這是一道多維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就是前輩給后輩做出貢獻的東西,后輩只能從前輩那里"學到東西"