4515: 又见背包

描述

有n种大小不同的数字 <nobr aria&#45;hidden="true"> ai </nobr> <math xmlns="http&#58;&#47;&#47;www&#46;w3&#46;org&#47;1998&#47;Math&#47;MathML"> <msub> <mi> a </mi> <mi> i </mi> </msub> </math>,每种 <nobr aria&#45;hidden="true"> mi </nobr> <math xmlns="http&#58;&#47;&#47;www&#46;w3&#46;org&#47;1998&#47;Math&#47;MathML"> <msub> <mi> m </mi> <mi> i </mi> </msub> </math>个,判断是否可以从这些数字中选出若干使它们的和恰好为k。 输入

输入包含多组数据。第一行为一个整数,代表数据组数,对于每组数据: 第一行输入n,k 第二行n个数,代表~. 第三行n个数,代表~.
输出

每组数据输出一行 满足条件能使得和恰好为k,输出”yes”. 否则输出”no”.

样例输入

1 2 2 1 1 2 2
样例输出

yes

这是动态规划的一种经典题型
这是matrix67大神的背包九讲的一种

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 105
#define MAXN 100005
#define mem(x,v) memset(x,v,sizeof(x))
int a[MAX];
int m[MAX];
int dp[MAXN];
int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) scanf("%d", &m[i]);
        mem(dp, -1);
        dp[0] = 0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=k;j++){
                if(dp[j]>=0) dp[j]=m[i];
                else if(j<a[i]||dp[j-a[i]]<=0) dp[j]=-1;
                else{
                    dp[j]=max(dp[j],dp[j-a[i]]-1);
                }//这是从一个博客看到的
            }
        }
        if (dp[k] >= 0) printf("yes\n");
        else printf("no\n");
    }
    return 0;
}
[Miracle_ma的专栏](http://blog.csdn.net/miracle_ma/article/details/51497619)

其中关键位置可以改为

for (int i = 1; i <= n; i++)
 {
   for (int j = 0; j <= k; j++) 
   {
     if (dp[j] >= 0) dp[j] = m[i];
     else if (j>=a[i] && dp[j - a[i]] > 0) 
          {
         dp[j] = max(dp[j], dp[j - a[i]] - 1);
                }
            }
        }