DP(背包问题)

1.01背包

N个物品,背包体积为V,每件物品最多只用一次。
每个问题两个属性:

  1. v i , w i v_{i},w_{i}
    在这里插入图片描述
    在这里插入图片描述

1.朴素写法

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;
int n,m;
int v[N],w[N];  //v[N]物品的体积,w[N]物品的价值
int f[N][N];  //物品的状态

int main(){

    cin >> n >> m;

    for(int i = 1;i <= n;i++)
        cin >> v[i] >> w[i];

    for(int i = 1;i <= n;i++)
        for(int j = 0;j <= m;j++){
            f[i][j] = f[i - 1][j];
            if(j >= v[i])
                f[i][j] = max(f[i][j],f[i - 1][j - v[i]] + w[i]);
        }

    cout << f[n][m] << endl;
    return 0;
}

2.优化写法

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;
int n,m;
int v[N],w[N];  //v[N]物品的体积,w[N]物品的价值
int f[N];  //物品的状态

int main(){

    cin >> n >> m;

    for(int i = 1;i <= n;i++)
        cin >> v[i] >> w[i];

    for(int i = 1;i <= n;i++)
        for(int j = m;j >= v[i];j--){
                f[j] = max(f[j],f[j - v[i]] + w[i]);
        }

    cout << f[m] << endl;
    return 0;
}

2.完全背包

N个物品,背包体积为V,每件物品有无限个。
在这里插入图片描述
在这里插入图片描述

1.朴素写法

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;
int n,m;
int v[N],w[N];
int f[N][N];

int main(){

    cin >> n >> m;
    for(int i = 1;i <= n;i++)
        cin >> v[i] >> w[i];

    for(int i = 1;i <= n;i++)
        for(int j = 0;j <= m;j++)
            for(int k = 0;k * v[i] <= j;k++){
                f[i][j] = max(f[i][j],f[i - 1][j - v[i] * k] + w[i] * k);
            }
    
    cout << f[n][m] << endl;

    return 0;
}

2.优化写法

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;
int n,m;
int v[N],w[N];
int f[N];

int main(){

    cin >> n >> m;
    for(int i = 1;i <= n;i++)
        cin >> v[i] >> w[i];

    for(int i = 1;i <= n;i++)
        for(int j = v[i];j <= m;j++){
            f[j] = max(f[j],f[j - v[i]] + w[i]);
        }
    cout << f[m] << endl;

    return 0;
}

3.多重背包

在这里插入图片描述
在这里插入图片描述

1.朴素写法

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n,m;
int v[N],w[N],s[N];
int f[N][N];

int main(){

    cin >> n >> m;

    for(int i = 1;i <= n;i++)
        cin >> v[i] >> w[i] >> s[i];

    for(int i = 1;i <= n;i++)
        for(int j = 0;j <= m;j++)
            for(int k = 0;k <= s[i] && k * v[i] <= j;k++){
                f[i][j] = max(f[i][j],f[i - 1][j - v[i] * k] + w[i] * k);
            }
    cout << f[n][m] << endl;

    return 0;
}

2.二进制优化写法

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 25000,M = 2010;

int n,m;
int v[N],w[N];
int f[N];

int main(){

    cin >> n >> m;

    int cnt = 0;
    for(int i = 1;i <= n;i++){
        int a,b,s;
        cin >> a >> b >> s;
        int k = 1;
        while(k <= s){
            cnt++;
            v[cnt] = a * k;
            w[cnt] = b * k;
            s -= k;
            k *= 2;
        }
        if(s > 0){
            cnt++;
            v[cnt] = a * s;
            w[cnt] = b * s;
        }
    }

    n = cnt;

    for(int i = 1;i <= n;i++)
        for(int j = m;j >= v[i];j--){
            f[j] = max(f[j],f[j - v[i]] + w[i]);
        }
    
    cout << f[m] << endl;

    return 0;
}

4.分组背包

在这里插入图片描述
在这里插入图片描述

优化写法

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n,m;
int v[N][N],w[N][N],s[N];
int f[N];

int main(){

    cin >> n >> m;
    for(int i = 1;i <= n;i++){
        cin >> s[i];
        for(int j = 0;j < s[i];j++){
            cin >> v[i][j] >> w[i][j];
        }
    }

    for(int i = 1;i <= n;i++)
        for(int j = m;j >= 0;j--)
            for(int k = 0;k < s[i];k++){
                if(v[i][k] <= j){
                    f[j] = max(f[j],f[j - v[i][k]] + w[i][k]);
                }
            }
    cout << f[m] << endl;

    return 0;
}
发布了52 篇原创文章 · 获赞 5 · 访问量 2254

猜你喜欢

转载自blog.csdn.net/advjj_058229/article/details/101568063