题目分析:
此题最大的特点就是有两中体积需要考虑。
1、每收集一个宠物需要消耗的球数w1[];
2、每收集一个宠物需要消耗的皮卡丘体力w2[];
此题的价值即为收集的宠物个数
状态表示:
f[i][j][k]; 前i个宠物中选,消耗球数不超过j并且消耗的体力不超过k的最大的收集宠物个数
状态计算
1.不要a[i]这个宠物,则什么都不消耗
f[i][j][k] = f[i - 1][j][k];
2.要a[i]这个宠物,需要的条件:j >= w1[i], k >= w2[i];
f[i][j][k] = f[i - 1][j - w1[i]][w2[i]] + 1;
代码实现:
# include <iostream>
using namespace std;
const int N = 1e3 + 10 , M = 510, K = 110;
int w1[K],w2[K]; //w1[]为需要耗费的球的数量,w2[]为需要消耗的体力
// int f[K][N][M]; //三维
int f1[N][M]; //二维
int n,m,k;
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(int i = 1 ; i <= k ; i++)
{
scanf("%d %d",&w1[i],&w2[i]);
}
/* //三维
for(int i = 1 ; i <= k ; i++)
{
for(int j = 0 ; j <= n ; j++)
{
for(int t = 0 ; t <= m - 1 ; t++)
{
f[i][j][t] = f[i - 1][j][t];
if(j >= w1[i] && t >= w2[i])
{
f[i][j][t] = max(f[i][j][t],f[i - 1][j - w1[i]][t - w2[i]] + 1);
}
}
}
}
printf("%d ",f[k][n][m - 1]);
int t1 = m - 1;
while(t1 > 0 && f[k][n][t1 - 1] == f[k][n][m])
{
t1--;
}
printf("%d\n",m - t1);
*/
for(int i = 1 ; i <= k ; i++)
{
for(int j = n ; j >= w1[i] ; j--)
{
for(int t = m - 1; t >= w2[i]; t--) //为什么最大为m - 1呢? 因为题意中皮卡丘体力为0的话,小精灵也不会被收服。所以就必须要保证当皮卡丘被减去体力之后值必须大于0.如果体力刚好等于0也无法收服它。所以体力消耗最大为m - 1.
{
f1[j][t] = max(f1[j][t] , f1[j - w1[i]][t - w2[i]] + 1);
}
}
}
printf("%d ",f1[n][m - 1]);
int t1 = m - 1;
while(t1 > 0 && f1[n][t1 - 1] == f1[n][m - 1]) //为什么直接用while使得t1从大到小遍历就可以了呢?因为根据f[i][j][k]的状态表示含义:前i只宠物,使用小于等于j个收集球,消耗小于等于k滴血用于收服宠物的最大个数。 所以当i,j相同时,消耗的血量越多的情况下f[][][]的值可能越大。因为血量少的情况包含在了血量多的情况之中,并取一个max。
{
t1 --;
}
printf("%d\n",m - t1);
return 0;
}