#include<bits/stdc++.h> 
using namespace std;  
int dp[1005];//滚动数组的写法,省下空间省不去时间  
int weight[1005];  
int value[1005];  
int main()  
{  
    int n,m;  
    cin>>m>>n;  
    memset(dp,0,sizeof(dp));  
    for(int i=1; i<=n; i++)  
        cin>>weight[i]>>value[i];  
    for(int i=1; i<=n; i++)//对每个数判断,可反  
    {  
        for(int j=m; j>=weight[i]; j--)//这里这个循环定死,不能反,反了就是完全背包 @
        {  
            dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);//其实不断在判断最优解,一层一层的  
        }  
    }  
    cout<<dp[m]<<endl;  
    return 0;  
}
解释@:
我们知道f[v]是由两个状态得来的,f[i-1][v]和f[i-1][v-c[i]],使用一维数组时,当第i次循环之前时,f[v]实际上就是f[i-1][v],得到第二个子问题
状态转移方程为:
我们可以与二维数组的状态转移方程对比一下
f(i,v) = max{ f(i-1,v), f(i-1,v-c[i])+w[i] }正如我们上面所说,f[v-c[i]]就相当于原来f[i-1][v-c[i]]的状态。如果将v的循环顺序由逆序改为顺序的话,就不是01背包了,就变成完全背包了,这个后面说。这里举一个例子理解为何顺序就不是01背包了
假设有物体z容量2,价值vz很大,背包容量为5,如果v的循环顺序不是逆序,那么外层循环跑到物体z时,内循环在v=2时,物体z被放入背包,当v=4时,寻求最大价值,物体z放入背包,f[4]=max{f[4],f[2]+vz},这里毫无疑问后者最大,那么此时f[2]+vz中的f[2]已经装入了一次物体z,这样一来该物体被装入背包两次了就,不符合要求,如果逆序循环v,这一问题便解决了。