码迷,mamicode.com
首页 > 其他好文 > 详细

背包问题

时间:2015-04-21 20:07:33      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:

一 01背包:

一件物品只能放一次

二维动态转移方程 dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])

降低空间复杂度用一维: dp[j] = max(dp[j],dp[j-w[i]]+v[i]), j 从V到0(为了防止数组越界,到w[i])

代码实现:

技术分享
#include<algorithm>
using namespace std;
const int MAX = 100;
int dp[MAX],w[MAX],v[MAX];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n ; i++){
        scanf("%d%d",&w[i],&v[i]);
    }
    for(int i = 1; i <= n ; i++){
        for(int j = m; j >= w[i]; j--){
            dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    printf("%d\n",dp[m]);
  return 0;
}
01背包

二 完全背包:

一件物品能放无限次

二维动态转移方程 dp[i][j] = max(dp[i-1][j],dp[i][j-w[i]]+v[i])

降低空间复杂度用一维:dp[j] = max(dp[j],dp[j-w[i]]+v[i]),不过j从0到V(为了防止数组越界,从w[i]开)

也可以看做m/(w[i])个物品,继续看成01背包问题,价值和重量都放大2^k次

代码实现:

技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 100;
int dp[MAX],w[MAX],v[MAX];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n ; i++){
        scanf("%d%d",&w[i],&v[i]);
    }
    for(int i = 1; i <= n ; i++){
        for(int j = w[i]; j <= m; j++){
            dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    printf("%d\n",dp[m]);
  return 0;
}
完全背包

三 多重背包:(hdu2191)

限定了每一件物品的适用次数

法一:

结合01背包和完全背包讨论情况

技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 1111;
int dp[MAX],w[MAX],v[MAX],t[MAX];
int n,m;
void comback(int w,int v)
{
    for(int i = w; i <= n ; i++)
        dp[i] = max(dp[i],dp[i-w]+v);
}
void oneback(int w,int v)
{
    for(int i = n ; i >= w; i--)
        dp[i] = max(dp[i],dp[i-w]+v);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= m ; i++){
            scanf("%d%d%d",&w[i],&v[i],&t[i]);
            if(w[i]*t[i] >= n) comback(w[i],v[i]);
            else {
                for(int j = 1; j < t[i]; j <<= 1){
                    oneback(j*w[i],j*v[i]);
                    t[i] -= j;
                }
                oneback(t[i]*w[i],t[i]*v[i]);
            }
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}
多重背包

法二:

转化成01背包问题,把每一种放大(二进制)    

技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 1111;
int dp[MAX],v[MAX],w[MAX],t[MAX];
int V[MAX],W[MAX];
int main()
{
    int n,m,T;
    scanf("%d",&T);
    while(T--){
        memset(dp,0,sizeof(dp));
        memset(v,0,sizeof(v));
        memset(w,0,sizeof(w));
        memset(t,0,sizeof(t));
        scanf("%d%d",&m,&n);
        int count = 1;
        for(int i = 1; i <= n ; i++){
            scanf("%d%d%d",&w[i],&v[i],&t[i]);
            for(int j = 1; j < t[i]; j <<= 1){
                V[count] = j*v[i];
                W[count] = j*w[i];
                count++;
                t[i] -= j;
            }
                V[count] = t[i]*v[i];
                W[count] = t[i]*w[i];
                count++;
        }
        for(int i = 1; i < count; i++){
            for(int j = m; j >= W[i];j--){
                dp[j] = max(dp[j],dp[j-W[i]]+V[i]);
                }
            }
        printf("%d\n",dp[m]);
        }
        return 0;
}
多重背包

四 多重 01 完全混合

五 二维条件的背包

只需要多开一个条件 dp[i][j][k] = max(dp[i-1][j][k],dp[i-1][j-a[i]][k-b[i]]+w[i])

六 分组的背包问题

多开一个for循环

技术分享
for(int k = 1; k <= n ;k++){
    for(int j = m; j >= 0 ; j--){
        for(int i = 1 ; i <= a[k]; i++){
            dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
}
分组背包
技术分享
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX = 110;
int dp[MAX];
int a[MAX][MAX];
int w[MAX],v[MAX];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)&&n&&m){
        memset(dp,0,sizeof(dp));
        memset(a,0,sizeof(a));
        memset(w,0,sizeof(w));
        memset(v,0,sizeof(v));
        for(int i = 1;i <= n ; i++){
            for(int j = 1; j <= m ; j++)
                scanf("%d",&a[i][j]);
        }
        for(int i = 1; i <= n ; i++){
            for(int j = m; j >= 0 ; j--){
                for(int k = 1; k <= j;k++){
                    dp[j] = max(dp[j],dp[j-k]+a[i][k]);
                }
            }
        }
        printf("%d\n",dp[m]);
    }
    return 0;
}
hdu1712

 

背包问题

标签:

原文地址:http://www.cnblogs.com/zero-begin/p/4445196.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!