01背包与完全背包的重新总结(dp深入学习后按自己的理解打出背包问题新算法)

//自己独创的完全背包,实际是01背包从前往后推的情况 (与3对照更好理解) 
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100010
int c[maxn],v[maxn],f[maxn];
int main(){
    ios::sync_with_stdio(false);
    int n,m,maxx=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>c[i]>>v[i];
    for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++) 
            if(j-c[i]>=0)
              f[j]=max(f[j],f[j-c[i]]+v[i]);
    cout<<f[m];
}

//其他人的完全背包 ,另一种从前往后推 
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],w[maxn],c[maxn];
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>m>>n;
    for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
    for(int i=1;i<=n;i++)
       for(int j=w[i];j<=m;j++)
          f[j]=max(f[j],f[j-w[i]]+c[i]);
    cout<<f[m];
}

//无可挑剔的01背包 
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],w[maxn],c[maxn];
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
    for(int i=1;i<=n;i++)//保证每个物品只放一次 
       for(int j=m;j>=w[i];j--)
          f[j]=max(f[j],f[j-w[i]]+c[i]);//除了初次更新外,状态量必须有一个已经被更新过 
    cout<<f[m];
}

3 10
8 5
3 4
6 3

//理想下的推导方式 
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=300001;
int f[maxn],w[maxn],c[maxn];
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
    for(int j=1;j<=m;j++)//imaginative
       for(int i=minn;i<=maxn;i+=x)
              f[j]=max(f[j],f[j-c[i]]+v[i]);
}

//发现从前往后推时,可以成立如第一份代码,但无法保证物品被取至多一次
//但是要满足子问题重叠(有一个状态量已被更新过),肯定有两种思路,从后往前或从前往后
//所以此时实验从后往前推 

 

posted @ 2017-11-02 10:15  TimDucan  阅读(217)  评论(0编辑  收藏  举报