分组背包题目

hdu 1712  ACboy needs your help 分组背包入门题目

http://acm.hdu.edu.cn/showproblem.php?pid=1712

题意:

acboy今年有n门课程,给出每门课程他授课多少天能获得的利润,w[i][j]表示第i个课程他如果授课j天可获得的利润,求在m天内它能够获得最大利润。

思路:
每门课程看做一个分组,每门课程对应着m个物品可选,直接套用分组背包即可。

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a , b) ((a) < (b) ? (a) : (b))
#define Max(a , b) ((a) > (b) ? (a) : (b))

#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 107
#define N 107
using namespace std;
//freopen("din.txt","r",stdin);

int f[N];
int w[N][N];

int main(){
   // freopen("din.txt","r",stdin);
    int i,j,k;
    int n,m;
    while (~scanf("%d%d",&n,&m)){
        if (!n && !m) break;
        for (i = 1; i <= n; ++i){
            for (j = 1; j <= m; ++j) scanf("%d",&w[i][j]);
        }
        CL(f,0);
        for (i = 1; i <= n; ++i){
            for (j = m; j >= 1; --j){
                for (k = 1; k <= j; ++k){//注意这里小于等于j
                    f[j] = max(f[j],f[j - k] + w[i][k]);
                }
            }
        }
        printf("%d\n",f[m]);
    }
    return 0;
}

 

hdu 3033 I love sneakers! 变形的分组背包(好题)

http://acm.hdu.edu.cn/showproblem.php?pid=3033

题意:

给出n个鞋子,每个鞋子分别对应着买它需要的费用,以及买完后获得的价值。这n个鞋子总共有m种品牌,保证每种品牌至少选择一个,求可能获得的最大价值。

思路:
这里保证每种品牌至少选择一个买了,所以才开始我利用num[i][j]表示到达i状态第j中品牌是否选了。而且也是空间优化到一维的结果超时了,算了算肯定超时。后来看了一下解题报告,才明白的。

首先f[i][j]表示选择了前i种商品,用了j的钱数所能得到的最大值,由于每种品牌至少选择一个所以只要把for循环变换一下即可保证能够多选某种品牌,但是这里怎么样保证由上一状态来的状态肯定选择了i-1呢,所以我们只需要dp[i - 1][j] != -1的因为这样的状态保证选择i-1这种状态,回想一下01背包的时候它会把-1覆盖成上一状态值,而这里不需要,还有这里c可能为0,我们必须首先保证最后计算由上一状态转移到该状态的值,否则如果先计算的话,就可能会造成一双鞋子买了多遍。。。

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a , b) ((a) < (b) ? (a) : (b))
#define Max(a , b) ((a) > (b) ? (a) : (b))

#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 10007
#define N 12
using namespace std;
//freopen("din.txt","r",stdin);

struct node{
    int c,w;
}tp;
int f[N][M];
vector<node>vc[N];

int Get(){
    char ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    int num = 0;
    while (ch >= '0' && ch <= '9'){
        num = num*10 + ch - '0';
        ch = getchar();
    }
    return num;
}
int main(){
    //freopen("din.txt","r",stdin);
    int i,j,k;
    int n,V,m;
    int a,b,c;
    while (~scanf("%d%d%d",&n,&V,&m)){
        for (i = 0; i <= m; ++i) vc[i].clear();
        for (i = 0; i < n; ++i){
            a = Get();
            b = Get();
            c = Get();
            tp.c = b; tp.w = c;
            vc[a].push_back(tp);//分类
        }
        for (i = 1; i <= m; ++i){
            for (j = 0; j <= V; ++j){
                f[i][j] = -1;
            }
        }
        for (i = 0; i <= V; ++i) f[0][i] = 0;//初始化

        for (i = 1; i <= m; ++i){
            int c,w;
            int len = vc[i].size();
            for (j = 0; j < len; ++j){
                 c = vc[i][j].c;
                 w = vc[i][j].w;
                for (k = V; k >= c; --k){
                   if (f[i][k - c] != -1)//必须先计算多选的情况
                   f[i][k] = max(f[i][k],f[i][k - c] + w);
                   if (f[i - 1][k - c] != -1)
                   f[i][k] = max(f[i][k],f[i - 1][k - c] + w);
                }
            }
        }
        if (f[m][V] == -1) puts("Impossible");
        else printf("%d\n",f[m][V]);

    }
    return 0;
}

 

待更新......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值