G - FATE
最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务。久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级。现在的问题是,xhd升掉最后一级还需n的经验值,xhd还留有m的忍耐度,每杀一个怪xhd会得到相应的经验,并减掉相应的忍耐度。当忍耐度降到0或者0以下时,xhd就不会玩这游戏。xhd还说了他最多只杀s只怪。请问他能升掉这最后一级吗?
Input
输入数据有多组,对于每组数据第一行输入n,m,k,s(0 < n,m,k,s < 100)四个正整数。分别表示还需的经验值,保留的忍耐度,怪的种数和最多的杀怪数。接下来输入k行数据。每行数据输入两个正整数a,b(0 < a,b < 20);分别表示杀掉一只这种怪xhd会得到的经验值和会减掉的忍耐度。(每种怪都有无数个)
Output
输出升完这级还能保留的最大忍耐度,如果无法升完这级输出-1。
Sample Input
10 10 1 10
1 1
10 10 1 9
1 1
9 10 2 10
1 1
2 2
Sample Output
0
-1
1
首先说一下我是一只小菜鸡,有说的不对的地方,欢迎批评,互怼啊
感觉dp就是就是对物品进行组合,来得到我们要的最优值,
1 )最重要的是你要搞清楚你的dp方程中下标的含义
2 ) 然后是状态转移的方程我们要想到达这个这个状态到底是从上面一个状态转换过来的,还是保留了自己最初的状态
就这一题目而言的话,有两个限制变量s,k,所以我们用二维来找出所有的状态
dp [i] [j]
i,表示杀了i个怪兽的时候,j表示我们使用了j的忍耐度的时候,显然我们用dp[i][j]保存的是在对应的这一个状态的最优值
我们想要到达这一个状态
dp[i][j] = max( dp[i][j] , dp[i-1][j-b] + a ) ;
保留本身的 由上面的那个转化来
还有就是完全背包,和0 1 背包的区别在哪里 从代码上来(完全)正着更新,(背包) 倒着更新(状态的更新顺序不一样)
题意的区别呢就是一个是物品的数量没有限制(完全),一个是数量有限制(01背包)之前的时候看人家的博客说是数量有限
和无限的原因,可能是自己太菜了没理解,不过今天晚上理解了
a b
物品 1 2 1 // a[1]=2, b[1]=1;
物品 2 1 1 // a[2]=1, b[2]=1;
1)对于完全背包而言正着更新
对于dp[1][1] 状态更新时间比 dp[2][2] 早,
拿第一件物品来更新某一状态的最优值的话,dp[1][1](最优值) = max( dp[1][1], dp[1-1][1-b[1]]+a[1] ) = 2 , 因为两个背包没装满并且数量无限,还要往下装dp[2][2] 最优值 = max( dp[2][2] , dp[2-1][2-a[1]] + a[1]) = 4 ;
拿第二件物品更新的时候 dp[1][1] = max( dp[1][1], dp[1-1][1-b[2]]+a[2] ) =2(第一件物品更新获得的值);
dp[2][2] = max( dp[2][2] , dp[2-1][2-b[2]]+a[2]) =4(第一次更新获得的值)
所以最后我们获得的dp[2][2]最优值是吃了两个1怪才活得的经验值(数量这里显然不是0 1 背包的一个);
2) 对于0 1 背包而言的话就是倒着更新 状态dp [2][2] 的更新比dp[1][1]要早
...........................................................(同上),dp[2][2]= max( dp[2][2] , dp[2-1][2-b[1]]+a[1] ) = 2,
dp[1][1] = max( dp[1][1], dp[1-1][1-b[1]]+a[1] ) =2 ,(这里我们会发现每一个状态都是值用了1怪不会重复杀);
...........................................................(同上),dp[2][2]=max( dp[2][2], dp[2-1][2-b[2]]+ a[2]) = 3
dp[1][1]=max( dp[1][1], dp[1-1][1-b[2]]+a[2])= 2 ;
这里的dp[2][2]的最优状态是杀一个1,一个2,并没有杀两个同种怪兽的情况;
#include <bits/stdc++.h>
using namespace std;
const int Max = 1e3+10;
typedef long long ll;
#define rep(i,s,n) for(int i=s;i<=n;i++)
#define per(i,n,s) for(int i=n;i>=s;i--)
int a[Max],b[Max],n,m,k,s;
ll dp[Max][Max];
int main(){
while(scanf("%d %d %d %d",&n,&m,&k,&s)!=EOF){
rep(i,1,k){
scanf("%d %d",&a[i],&b[i]);
}
memset(dp,0,sizeof(dp));
int max1=-1;
rep(z,1,k){
rep(i,1,s){
rep(j,b[z],m){
if(dp[i][j]<dp[i-1][j-b[z]]+a[z]){
dp[i][j]=dp[i-1][j-b[z]]+a[z];
if(max1<m-j&&dp[i][j]>=n){
max1=m-j;
}
}
}
}
}
printf("%d\n",max1);
}
return 0;
}