01背包 -题目

目录

 A.  基本0-1背包

B.  采药

C.  选取整数

D.  noip2001普及组 4.装箱问题

E.  买菜做饭

F.  美丽手镯

G.  竞赛真理

H.  noip2006普及组 2.开心的金明(选做)

I.  抢劫银行(选做)

J.  大盗阿福(选做)


  

 A.  基本0-1背包

时间:1s   空间:128M

题目描述:

一个旅行者有一个最多能用m公斤的背包,现在有n件物品,它们的重量分别是W1, W2, ..., Wn,它们的价值分别为C1, C2, ..., Cn。若每种物品只有一件,求旅行者能获得的最大总价值。

输入格式:

第一行:两个整数,M(背包容量,M<=200) 和 N(物品数量,N<=30);

第2...N+1行:每行二个整数 Wi, Ci,表示每个物品的重量和价值。

输出格式:

仅一行,一个数,表示最大总价值

样例输入:

10 4

2  1

3  3

4  5

7  9

样例输出:

12
#include<bits/stdc++.h>
using namespace std;
int m, n;
int w[205], c[205];
int f[205]; 
int main(){
    scanf("%d%d",&m, &n);  
    for (int i=1; i <= n; i++)
        scanf("%d%d",&w[i],&c[i]); 
    for (int i=1; i <= n; i++)   
        for (int v = m; v >= w[i]; v--)
            if (f[v-w[i]]+c[i]>f[v])
                f[v] = f[v-w[i]]+c[i];
    printf("%d",f[m]);     
	return 0;
}

B.  采药

题目描述:

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式:

第一行有2个整数T(1≤T≤1000)和M(1≤M≤100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。
接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式:

1个整数,表示在规定的时间内可以采到的草药的最大总价值。

样例输入1

70   3

71   100

69   1

1   2

样例输出1

3

#include <bits/stdc++.h>
using namespace std;
int dp[1000000];
int a[10100];
int v[10100];
int main(){
	int t,m;
	cin>>t>>m;
	for(int i=1; i<=m; i++){
		cin>>v[i]>>a[i];
	}
	for(int i=1; i<=m; i++){
		for(int j=t; j>=v[i]; j--){
			dp[j]=max(dp[j],dp[j-v[i]]+a[i]);
		}
	}
	cout<<dp[t];
	return 0;
}

C.  选取整数

题目描述

从 1 到 n 中选择若干个数,它们的总和不超过 n。 每个选择的数字都有自己的约数个数。
将这些数的约数个数相加,您可以得到一个总和。 找出这些所选数字的最大约数个数总和。 
注意:这个总和不是那些选择的数字的总和,而是约数个数的总和。

输入样例

2

输出样例

2

数据约定

n<=1000

时间和空间约定

1s ,512M

#include<bits/stdc++.h>
using namespace std; 
int sum[1010],dp[1010];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			if(i%j==0){
				sum[i]++;
			}
		}	
	}
	for(int i = 1;i <=n; i++){
		for(int j = n ; j>= i; j--){
			dp[j] = max(dp[j],dp[j-i] + sum[i]);
		}
	}
	cout<<dp[n];
	return 0;
}

D.  noip2001普及组 4.装箱问题

时间:1s   空间:128M

题目描述:

有一个箱子容量为V(正整数,0≤V≤20000),同时有n个物品( 0<n≤30 ),每个物品有一个体积(正整数)。

要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

输入格式:

1个整数,表示箱子容量

1个整数,表示有n个物品

接下来n行,分别表示这n个物品的各自体积

输出格式:

1个整数,表示箱子剩余空间。

样例输入1:

24

6

8

3

12

7

9

7

样例输出1:

0

说明:NOIp2001普及组 第4题

#include<bits/stdc++.h>
int dp[20005];
int box[40];
int max(int a,int b){
	if(a>=b) return a;
	return b;
}
int main(){
	int v,n;
	scanf("%d%d",&v,&n);
	for(int i = 0;i<n;i++){
		scanf("%d",&box[i]);
	}
	for(int i = 0;i < n; i++){
		for(int j = v ; j>= box[i]; j--){
			dp[j] = max(dp[j],dp[j-box[i]] + box[i]);
		}
	}
	printf("%d",v-dp[v]);
	
	return 0;
}

E.  买菜做饭

Description

为了做饭,出题人拿了 k 块钱,准备去买食材。出题人准备买一只螃蟹和若干蔬菜。菜场里有 n 只螃蟹,第 i只螃蟹的价格为 c_i​,美味值为 v_i,菜场里有 m 个蔬菜,第 i 个蔬菜的价格为 w_i,美味值为 p_i​,求出题人的钱能换来最大的美味值。

Input

第一行三个正整数 k,n,m,
接下来 n 行,每行两个正整数 c_i​,v_i,
接下来 m 行,每行两个正整数 w_i​,p_i,
相邻整数均以空格分开

Output

一行一个整数,表示出题人的钱能换来最大的美味值

Sample input

23 2 2

2 3

3 4

10 10

10 10

Sample output

24

Note

all the numbers <= 3000

Time and memory limit

1s ,512M

#include<bits/stdc++.h>
using namespace std;
int w[3010],v[3010],c[3010];
int p[3010],dp[3010];
int main(){
    int k,m,n;
    cin>>k>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>v[i];
    }
    for(int i=1;i<=m;i++){
        cin>>w[i]>>p[i];
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=k;j>=w[i];j--)
        {
            dp[j]=max(dp[j],dp[j-w[i]]+p[i]);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=c[i];j<=k;j++)
        {
            ans=max(ans,dp[j-c[i]]+v[i]);
        }
    }
    printf("%d\n",ans);
    return 0;
}

F.  美丽手镯

时间:0.2s   空间:32M

题目描述:

有N个美丽的手镯,每个手镯有一个重量与美丽值,现在只能拿走最重总和不超过M的手镯,求最大的美丽值之和

输入格式:

第一行输入两个整数N,M

第二行到第N+1行每行输入两个整数Wi,Di,表示重量与美丽值

输出格式:

输出一个整数

样例输入:

4 6

1 4

2 6

3 12

2 7

样例输出:

23

约定:

1<=N<=3402,1<=M<=12880,1<=Wi<=400,1<=Di<=100

#include <bits/stdc++.h>
using namespace std;
const int maxn=3500,maxw=13000;
int n,m;
int w[maxn],v[maxn],dp[maxw];
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;
 }

G.  竞赛真理

TENSHI在经历了无数次学科竞赛的失败以后,得到了一个真理:做一题就要对一题!但是要完全正确地做对一题是要花很多时间(包括调试时间),而竞赛的时间有限。所以开始做题之前最好先认真审题,估计一下每一题如果要完全正确地做出来所需要的时间,然后选择一些有把握的题目先做。 当然,如果做完了预先选择的题目之后还有时间,但是这些时间又不足以完全解决一道题目,应该把其他的题目用贪心之类的算法随便做做,争取“骗”一点分数。

输入格式:

第一行有两个正整数N和T,表示题目的总数以及竞赛的时限(单位秒)。以下的N行,每行4个正整数W1i 、T1i 、W2i 、T2i ,分别表示第i题:完全正确做出来的得分,完全正确做出来所花费的时间(单位秒),“骗”来的分数,“骗”分所花费的时间(单位秒)。

输出格式:

根据每一题解题时间的估计值,确定一种做题方案(即哪些题目认真做,哪些题目“骗”分,哪些不做),使能在限定的时间内获得最高的得分,

样例输入:

4 10800

18 3600 3 1800

22 4000 12 3000

28 6000 0 3000

32 8000 24 6000

样例输出:

50

数据范围:

3≤N≤30,2≤T≤1080000,1≤ W1i 、W2i ≤30000,1≤T1i 、T2i≤T

时间限制:

1000

空间限制:

65536

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1080010;
int n , T;
int w1[MAXN],t1[MAXN],w2[MAXN],t2[MAXN];
int dp[MAXN];
 
int solve(){
    memset(dp , 0 , sizeof(dp));
    int ans = 0;
    for(int i = 1 ; i <= n ; i++){
       for(int j = T ; j >= 0 ; j--){
           int tmp = dp[j];
           if(j >= t1[i])
               tmp = max(tmp , dp[j-t1[i]]+w1[i]);
           if(j >= t2[i])
               tmp = max(tmp , dp[j-t2[i]]+w2[i]);
           dp[j] = max(dp[j] , tmp);
           ans = max(dp[j] , ans);
       }   
    }
    return ans;
}
int main(){
	scanf("%d%d" , &n , &T);
    for(int i = 1 ; i <= n ; i++) 
        scanf("%d%d%d%d" , &w1[i] , &t1[i] , &w2[i] , &t2[i]);
    printf("%d\n" , solve()); 

    return 0;
}

H.  noip2006普及组 2.开心的金明(选做)

时间:1s   空间:256M

题目描述:

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:
v[j1]*w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中*为乘号)
请你帮助金明设计一个满足要求的购物单。

输入格式:

第一行,两个整数,用空格分隔,N,m(N(<30000)表示总金额,m(<25)表示所需的项目。)
从第二行到第m + 1行,第j行给出了编号为j-1的项目的基本数据,每行有2个非负整数v和w(其中v是项目的价格(v <= 10000),w是项目的重要性(1~5))

输出格式:

一个整数,即产品价格和项目重要性的最大总和,而不是总金额(<100000000)。

样例输入:

1000 5

800 2

400 5

300 5

400 3

200 2

样例输出:

3900
时限:
1S

#include<bits/stdc++.h>
using namespace std; 
int f[30010];
int v[30010],p[30010];
int main()
{
	int k,n;
	cin>>k>>n;
	for(int i=1;i<=n;i++)
		cin>>v[i]>>p[i];
	for(int i=1;i<=n;i++)
		for(int j=k;j>=v[i];j--)
			f[j]=max(f[j],f[j-v[i]]+v[i]*p[i]);
	cout<<f[k];
	return 0;
}

I.  抢劫银行(选做)

题目描述

一个劫匪要去抢劫n家银行,每家银行有一定的现金,每抢一家银行该劫匪有一定几率被警察抓住,但是当该劫匪被抓住的几率小于p时他可以逃脱,问该劫匪在不被捕的情况下最多能抢到多少钱?

输入格式

第一行为用例组数T,每组用例第一行为一个浮点数P和一个整数n分别表示被捕的几率上限以及该劫匪计划抢劫的银行数量,之后n行每个一个整数M和一个浮点数p表示该家银行的现金数以及该劫匪抢劫该家银行被捕的几率

0<T≤100

0.0≤P≤1.0

0<n≤100

0≤Mj≤100

0.0≤pj≤1.0

输出格式

对于每组用例,输出该劫匪在不被捕的情况最多能抢到多少钱

样例输入

3

0.04 3

1 0.02

2 0.03

3 0.05

0.06 3

2 0.03

2 0.03

3 0.05

0.10 3

1 0.03

2 0.02

3 0.05

样例输出

2

4

6

时空限制

1s,512M

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;
double dp[11234],pp[233];
int val[233];
int main(){
    int t;
    double p;
    int n;
    scanf("%d",&t);
    for(int z = 1; z <= t; ++z){
        scanf("%lf%d",&p,&n);
        int mx = 10000;
        for(int i = 0; i <= mx; ++i)
            dp[i] = -1;
        dp[0] = 0;
        for(int i = 0; i < n; ++i){
            scanf("%d%lf",&val[i],&pp[i]);
            for(int j = mx; j >= val[i]; --j)
            {
                if(dp[j-val[i]] != -1)
                {
                    if(dp[j] == -1) dp[j] = dp[j-val[i]]*(1-pp[i])+pp[i];
                    else dp[j] = min(dp[j],dp[j-val[i]]*(1-pp[i])+pp[i]);
                }
            }
        }

        for(int i = mx; i >= 0; --i)
        {
            if(dp[i] != -1 && dp[i] < p)
            {
                printf("%d\n",i);
                break;
            }
        }
    }

    return 0;
}

J.  大盗阿福(选做)

描述 


阿福是一名经验丰富的大盗。趁着月黑风高,阿福打算今晚洗劫一条街上的店铺。

这条街上一共有 N 家店铺,每家店中都有一些现金。阿福事先调查得知,只有当他同时洗劫了两家相邻的店铺时,街上的报警系统才会启动,然后警察就会蜂拥而至。

作为一向谨慎作案的大盗,阿福不愿意冒着被警察追捕的风险行窃。他想知道,在不惊动警察的情况下,他今晚最多可以得到多少现金?


【输入】
输入的第一行是一个整数 T (T <= 50) ,表示一共有 T 组数据。
接下来的每组数据,第一行是一个整数 N (1 <= N <= 100, 000) ,表示一共有 N 家店铺。第二行是 N 个被空格分开的正整数,表示每一家店铺中的现金数量。每家店铺中的现金数量均不超过 1000 。


【输出】
对于每组数据,输出一行。该行包含一个整数,表示阿福在不惊动警察的情况下可以得到的现金数量。


样例输入

2

3

1 8 2

4 10 7 6 14
样例输出

8

24
提示
对于第一组样例,阿福选择第 2 家店铺行窃,获得的现金数量为 8 。
对于第二组样例,阿福选择第 1 和 4 家店铺行窃,获得的现金数量为 10 + 14 = 24 。

#include<bits/stdc++.h>
using namespace std;
int a[100005],f[100005];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        memset(a,0,sizeof(0));
        memset(f,0,sizeof(0));
        scanf("%d",&a[1]);
        f[1]=a[1];
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&a[i]);
            f[i]=max(f[i-1],f[i-2]+a[i]);
        }
            
        cout<<f[n]<<endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值