01背包问题

hdu 2546 饭卡

饭卡

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 27976    Accepted Submission(s): 9706


Problem Description
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
 

Input
多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。

n=0表示数据结束。
 

Output
对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
 

Sample Input
  
  
1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0
 

Sample Output
  
  
-45 32
 

Source

思路:对于饭卡上的余额,有明确的的规定,当大于等于5元时,才可以买别的东西,那么我们可以先预留5元,从给出的物品中买一件最贵的物品,另外的余额用来购买其他的物品,这时就转化成了在给定余额的情况下,能够最大获得多少价值?每种物品只有一种,就是01背包问题。

代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[1001][1001];
int value[1001];
int max(int a, int b) {
    return a > b ? a : b;
}

void judge(int sum, int Max, int n) {
    int i, j;
    for(i = 1; i <= n-1; i++)
        for(j = 0; j <= sum-5; j++) {
            dp[i][j] = dp[i-1][j];
            if(j >= value[i])
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-value[i]] + value[i]);
        }
    printf("%d\n", sum - dp[n-1][sum-5] - Max);
 }

int compare(int a, int b) {
    return a < b;
}

int main() {
    int n, i, j, sum;
    memset(dp, 0, sizeof(int)*1001*1001);
    while(scanf("%d", &n), n != 0) {
        for(i = 1; i <= n; i++)
            scanf("%d", &value[i]);
        scanf("%d", &sum);
        if(sum < 5) {
            printf("%d\n",sum);
            continue;
        }
        sort(value+1, value + n +1, compare);
        judge(sum, value[n], n);
    }
}

一维数组实现:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[1003];
int value[1003];
int max(int a, int b) {
    return a > b ? a : b;
}

void judge(int sum, int Max, int n) {
    int i, j;
    for(i = 1; i <= n-1; i++)
        for(j = sum-5; j >= value[i]; j--) {
                dp[j] = max(dp[j], dp[j-value[i]] + value[i]);
        }
    printf("%d\n", sum - dp[sum-5] - Max);
 }

int compare(int a, int b) {
    return a < b;
}

int main() {
    int n, i, j, sum;
    while(scanf("%d", &n), n != 0) {
        memset(dp, 0, sizeof(int)*1003);
        memset(value, 0, sizeof(int)*1003);
        for(i = 1; i <= n; i++)
            scanf("%d", &value[i]);
        scanf("%d", &sum);
        if(sum < 5) {
            printf("%d\n",sum);
            continue;
        }
        sort(value + 1, value + n + 1, compare);
        judge(sum, value[n], n);
    }
}

hdu 1171  big event in hdu

Big Event in HDU

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 40252    Accepted Submission(s): 13861


Problem Description
Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don't know that Computer College had ever been split into Computer College and Software College in 2002.
The splitting is absolutely a big event in HDU! At the same time, it is a trouble thing too. All facilities must go halves. First, all facilities are assessed, and two facilities are thought to be same if they have the same value. It is assumed that there is N (0<N<1000) kinds of facilities (different value, different kinds).
 

Input
Input contains multiple test cases. Each test case starts with a number N (0 < N <= 50 -- the total number of different facilities). The next N lines contain an integer V (0<V<=50 --value of facility) and an integer M (0<M<=100 --corresponding number of the facilities) each. You can assume that all V are different.
A test case starting with a negative integer terminates input and this test case is not to be processed.
 

Output
For each case, print one line containing two integers A and B which denote the value of Computer College and Software College will get respectively. A and B should be as equal as possible. At the same time, you should guarantee that A is not less than B.
 

Sample Input
  
  
2 10 1 20 1 3 10 1 20 2 30 1 -1
 

Sample Output
  
  
20 10 40 40
 

Author
lcy

思路:要求把给定的所有的物品,一分为二,要求A份要大于等于B份,可以先把总的物品的价值所出来,除以2以此作为背包容量,计算最大值,一定会使得A份大于等于B份。与01背包不同的是,它的数量不一定都是1,这个题更像多重背包,可以把它转换为01背包,把n件相同的物品,看做n件(具有相同价值)不同的物品,这时只不过weight和value数组的长度变长了,其他没有什么区别。

代码:

#include<stdio.h>
#include<string.h>
int value[5020];
int dp[250020];
int max(int a, int b) {
    return a > b ? a : b;
}
void judge(int sum, int sumValue) {
    int average = sumValue / 2;
    int i, j;
    for(i = 1; i <= sum; i++)
        for(j = average; j >= value[i]; j--) {
            dp[j] = max(dp[j-value[i]] + value[i], dp[j]);
        }
    printf("%d %d\n", sumValue - dp[average], dp[average]);
}
int main() {
    int n, i, j, count, sum, sumValue, a, b;
    while(scanf("%d", &n), n > 0) {
        memset(value, 0, sizeof(value));
        memset(dp, 0, sizeof(dp));
        sum = 1;
        sumValue = 0;
        for(i = 1; i <= n; i++) {
            scanf("%d", &a);
            scanf("%d", &b);
            while(b--) {
                value[sum++] = a;
                sumValue += a;
            }
        }
        judge(sum, sumValue);
    }
 }

HDU2602:Bone Collector

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


经典的01背包问题,

代码:

#include<stdio.h>
#include<string.h>
int dp[1005];
int value[1005];
int weight[1005];
int v, n;
int max(int a, int b) {
    return a > b ? a : b;
}
void judge() {
    int i, j;
    for(i = 1; i <= n; i++)
        for(j = v; j >= weight[i]; j--)
            dp[j] = max(dp[j], dp[j-weight[i]] + value[i]);
    printf("%d\n", dp[v]);
}
int main() {
    int t, i;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &v);
        memset(dp, 0, sizeof(dp));
        memset(value, 0, sizeof(value));
        memset(weight, 0, sizeof(weight));
        for(i = 1; i <= n; i++)
            scanf("%d", &value[i]);
        for(i = 1; i <= n; i++)
            scanf("%d", &weight[i]);
        judge();
    }
}

HDU 2639  Bone Collector II

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

这里要求第k优解,

代码:

#include<stdio.h>
#include<string.h>
int value[1005];
int weight[1005];
int dp[1005][32];
int n, v, k;
void judge() {
    int x, y, z;
    int i, j, t;
    int a[32] = {0}, b[32]= {0};
    for(i = 1; i <= n; i++) {

        for(j = v; j >= weight[i]; j--) {

            for(t = 1; t <= k; t++) {
                a[t] = dp[j-weight[i]][t] + value[i];
                b[t] = dp[j][t];
            }
            x = y = z = 1;
            a[t] = b[t] = -1;

            while(z <= k && (x <= k || y <= k)) {
                if(a[x] > b[y]) {
                    dp[j][z] = a[x];
                    x++;
                }
                else {
                    dp[j][z] = b[y];
                    y++;
                }
                if(dp[j][z] != dp[j][z-1])
                    z++;
            }
        }
    }
    printf("%d\n", dp[v][k]);
}

int main() {
    int t, i;
    scanf("%d", &t);
    while(t--) {
        memset(value, 0, sizeof(value));
        memset(weight, 0, sizeof(weight));
        memset(dp, 0, sizeof(int)*1005*32);
        scanf("%d%d%d", &n, &v, &k);
        for(i = 1; i <= n; i++)
            scanf("%d", &value[i]);
        for(i = 1; i <= n; i++)
            scanf("%d", &weight[i]);
        judge();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值