标签:name problem for 状态 概率 世界 一点 搞笑 ble
背包问题
因为题目中有两个限制条件,所以并不能当做一般背包问题来做,
既然限制条件(类似于"体积")多了一个,那么现在维数也多开一维,同时表示其状态
我们又发现,这个题每种物品(需求)只能取一次,所以这是一道多维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就是前辈给后辈做出贡献的东西,后辈只能从前辈那里"学到东西"
标签:name problem for 状态 概率 世界 一点 搞笑 ble
原文地址:https://www.cnblogs.com/648-233/p/11346039.html