10 100 5
7 10
2 40
2 50
1 20
4 20
3 30
这道题目一看就是最优子结构的问题,当然,也是类似于背包的一种动态规划,叫做多约束背包,这种背包有多个约束(当然,看上去和01背包很相似,都是一个物品只能选择要或者不要),如皮卡丘体力的约束、野生小精灵数量的约束、精灵蛋的约束。是所以这类背包是与01背包不同的。
因为本道题目只有3个约束,所以,就要设置一个三维数组:
dp[i][j][k]代表前i个野生小精灵,假如皮卡丘有j的体力值,小智有k个精灵蛋时最多能获得的精灵数量。
因为这道题目还要求如果可以收服的小精灵数量一样,小智希望皮卡丘受到的伤害越小(剩余体力越大),所以还要设置另一个数组来记录皮卡丘最多的体力值。
f[i][j][k]代表前i个野生小精灵,假如皮卡丘有j的体力值,小智有k个精灵蛋时最多剩余的体力值。
按照01背包的思路来写状态转移方程,也并不难。
dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-w[i]][k-t[i]]+1);
if(dp[i-1][j][k]>=dp[i-1][j-w[i]][k-t[i]]+1) f[i][j][k]=j;
else f[i][j][k]=j-w[i];
第一个数组,是为了比较选择还是放弃来决策出最优解的,如果不选就是:dp[i-1][j][k];如果选择,那么皮卡丘的体力值和小智的精灵蛋就要减少,但是精灵的数量就会加1,所以此状态就是:dp[i-1][j-w[i]][k-t[i]]+1,去两者之间的较大者,就是可以获得的最多的精灵数量。
第二个数组,如果选择不收服精灵较优,那么皮卡丘的体力就不会减少,即:f[i][j][k]=j,否则,那还是要收服这个精灵的所以皮卡丘的体力时就会相对应的减少,即:f[i][j][k]=j-w[i]。
第一个数组:
因为如果精灵的数量为0或者皮卡丘的体力值是0或者是小智的精灵蛋的数量是0,那么,就只能收服0只野生精灵,即:
若i=0或者j=0或者k=0,那么dp[i][j][k]=0;
第二个数组:
因为如果皮卡丘的体力值不为0,那么最大的体力值也不为0,即:
若体力值不为0,那么就等于其体力值(i=0或者k=0)
f[i][j][k]=j;
否则
f[i][j][k]=0;
因为要考虑到三的约束条件(三个变量),所以找到提的时间复杂度是:O(NMK)
因为:N(0 < N < 1000),M(0 < M < 500),K(0 < K < 100),所以总时间复杂度是:1000500100=50000000(五千万),不会超时。
#include
#include
using namespace std;
const int maxn = 1e3+5;
int dp[1005][505];
int a[maxn], b[maxn];
int main()
{
int n, m, k;
cin>>n>>m>>k;
for (int i = 1 ; i <= k ; i ++)
cin >> a[i] >> b[i];
for (int t = 1 ; t <= k ; t ++)
for (int i = n ; i >= a[t] ; i --)
for (int j = m ; j >= b[t] ; j --)
dp[i][j] = max(dp[i][j], dp[i-a[t]][j-b[t]] + 1);
int ans1 = 0, ans2 = m;
for (int i = 1 ; i <= m ; i ++)
if (dp[n][i] > ans1)
{
ans1 = dp[n][i];
ans2 = m - i;
}
cout << ans1 << ' ' << ans2 << endl;
return 0;
}