目录
A. NASA的食物计划
题目背景
NASA(美国航空航天局)因为航天飞机的隔热瓦等其他安全技术问题一直大伤脑筋,因此在各方压力下终止了航天飞机的历史,但是此类事情会不会在以后发生,谁也无法保证,在遇到这类航天问题时,解决方法也许只能让航天员出仓维修,但是多次的维修会消耗航天员大量的能量,因此NASA便想设计一种食品方案,让体积和承重有限的条件下多装载一些高卡路里的食物.
题目描述
航天飞机的体积有限,当然如果载过重的物品,燃料会浪费很多钱,每件食品都有各自的体积、质量以及所含卡路里,在告诉你体积和质量的最大值的情况下,请输出能达到的食品方案所含卡路里的最大值,当然每个食品只能使用一次.
输入格式
第一行 两个数 体积最大值(<400)和质量最大值(<400)
第二行 一个数 食品总数N(<50).
第三行-第3+N行
每行三个数 体积(<400) 质量(<400) 所含卡路里(<500)
输出格式
一个数 所能达到的最大卡路里(int范围内)
输入样例
320 350
4
160 40 120
80 110 240
220 70 310
40 400 220
输出样例
550
#include<bits/stdc++.h>
using namespace std;
int a[55],b[55],c[55];
int dp[505][505];
int main(){
int v,w,n;
cin>>v>>w>>n;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i]>>c[i];
for(int i=1;i<=n;i++){
for(int j=v;j>=a[i];j--){
for(int k=w;k>=b[i];k--)
dp[j][k]=max(dp[j][k],dp[j-a[i]][k-b[i]]+c[i]);
}
}
cout<<dp[v][w]<<endl;
return 0;
}
B. 潜水员
时间:1s 空间:128M
题目描述:
现有一些带两种气体(氧气和氮气)的气缸,潜水员为了完成工作需要特定数量的氧和氮,每个气缸都有自身的重量和两种气体的含量。请问潜水员所需携带气缸的最小总重量是多少?
例如:有5个气缸。每行三个数字为:氧,氮的含量和气缸的重量:
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
如果潜水员需要5升的氧和60升的氮,则总重最小为249(携带1,2或者携带4,5号气缸)。
输入格式:
第一行有2整数m,n(1≤m≤21,1≤n≤79)。它们表示氧,氮各自需要的量。
第二行为整数k(1≤k≤1000)表示气缸的个数。
此后的k行,每行包括ai,bi,ci(1≤ai≤21,1≤bi≤79,1≤ci≤800)3个整数。这些各自是:第i个气缸里的氧和氮的容量及汽缸重量。
输出格式:
仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。
样例输入:
5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
样例输出:
249
#include <bits/stdc++.h>
using namespace std;
int m, n, k;
int a[1005], b[1005], c[1005];
int dp[1005][30][85];
int main(){
scanf("%d%d", &m, &n);
scanf("%d", &k);
for(int i = 1; i <= k; ++i){
scanf("%d%d%d", &a[i], &b[i], &c[i]);
}
memset(dp, 0x3f, sizeof dp);
dp[0][0][0] = 0;
for(int i = 1; i <= k; ++i){
for(int j = m; j >= 0; --j){
for(int g = n; g >= 0; --g){
dp[i][j][g]=min(dp[i-1][j][g],dp[i-1][max(0,j-a[i])][max(0,g-b[i])]+c[i]);
}
}
}
printf("%d\n", dp[k][m][n]);
return 0;
}
Runtime Error:
#include <bits/stdc++.h>
using namespace std;
int m, n, k;
int a[1005], b[1005], c[1005];
int dp[30][85][1005];
int main(){
scanf("%d%d", &m, &n);
scanf("%d", &k);
for(int i = 1; i <= k; ++i){
scanf("%d%d%d", &a[i], &b[i], &c[i]);
}
memset(dp, 0x3f, sizeof dp);
dp[0][0][0] = 0;
for(int i = 1; i <= k; ++i){
for(int j = m; j >= 0; --j){
for(int g = n; g >= 0; --g){
dp[i][j][g]=min(dp[i-1][j][g],dp[i-1][max(0,j-a[i])][max(0,g-b[i])]+c[i]);
}
}
}
printf("%d\n", dp[k][m][n]);
return 0;
}
C. 分组背包
时间:1s 空间:128M
题目描述:
一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
输入格式:
第1行:三个整数,V(背包容量,V<=200),N(物品数量,N<=30)和T(最大组号,T<=10);
第2..N+1行:每行三个整数Wi,Ci,P,表示每个物品的重量,价值,所属组号。
输出格式:
仅一行,一个数,表示最大总价值。
样例输入:
10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3
样例输出:
20
#include<bits/stdc++.h>
using namespace std;
int w[10000],q[10000],p[1000][1000],dp[10000];
int main(){
int s;
int v,n,t;
cin>>v>>n>>t;
for(int i=1;i<=n;i++){
cin>>w[i]>>q[i]>>s;
p[s][0]++;
p[s][p[s][0]]=i;
}
for(int i=1;i<=t;i++){
for(int j=v;j>=0;j--){
for(int k=1;k<=p[i][0];k++){
if(j>=w[p[i][k]]){
dp[j]=max(dp[j],dp[j-w[p[i][k]]]+q[p[i][k]]);
}
}
}
}
cout<<dp[v];
return 0;
}
D. 混合背包
时间:1s 空间:128M
题目描述:
一个旅行者有一个最多能用V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
输入格式:
第一行:二个整数,V(背包容量,V<=200),N(物品数量,N<=30);
第2..N+1行:每行三个整数Wi,Ci,Pi,前两个整数分别表示每个物品的重量,价值,第三个整数若为0,则说明此物品可以购买无数件,若为其他数字,则为此物品可购买的最多件数 (0≤Pi≤20) 。
输出格式:
仅一行,一个数,表示最大总价值。
样例输入:
10 3
2 1 0
3 3 1
4 5 4
样例输出:
11
提示:
选第一件物品1件和第三件物品2件。
#include <bits/stdc++.h>
using namespace std;
int v,n;
int w[35],c[35],p[35],f[205];
int main() {
cin>>v>>n;
for(int i=1; i<=n; i++) {
cin>>w[i]>>c[i]>>p[i];
}
for(int i=1; i<=n; i++) {
if(p[i]==0) {
for(int j=w[i]; j<=v; j++) {
f[j]=max(f[j-w[i]]+c[i],f[j]);
}
} else if(p[i]==1) {
for(int j=v; j>=w[i]; j--) {
f[j]=max(f[j-w[i]]+c[i],f[j]);
}
} else {
for(int j=v; j>=w[i]; j--) {
for(int k=0; k<=p[i]; k++) {
if(j-k*w[i]<0) {
break;
}
f[j]=max(f[j-k*w[i]]+k*c[i],f[j]);
}
}
}
}
cout<<f[v];
}
E. 愚公移山
题目描述
【版权说明】
本题为改编题。
【问题描述】
愚公移山的故事相信大家都听过,愚公日复一日的劳作,终于还需要再搬走至少体积为 m 的石头这条路就畅通了,已知每块的体积和把它移走需要的体力分别为 vi 和 wi。愚公已经移山移了这么长时间了,他也很累了,他还剩下的体力为c。
输入格式
输入文件的第一行是三个整数:m、n、c。(1≤m,n,c≤10000)
接下来 n 行,每行两个整数:分别为每块石头的体积 vi 和移走需要的体力 wi。(1≤vi,wi≤1000)
输出格式
输出文件只有一行,如果愚公能把山移完,则输出他把山移完剩下的最大的体力,否则输出 "Impossible"(不带引号)。
输入输出样例
输入 #1
100 2 10
50 5
50 5
输出 #1
0
输入 #2
10 2 1
50 5
10 2
输出 #2
Impossible
#include <bits/stdc++.h>
using namespace std;
int m, n, c;
int v[10005], w[10005];
int dp[10005];
int main(){
cin>>m>>n>>c;
for(int i = 1; i <= n; i++){
cin>>v[i]>>w[i];
}
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for(int i = 1; i <= n; ++i){
for(int j = m; j >=0; j--){
dp[j]=min(dp[j],dp[max(0,j-v[i])]+w[i]);
}
}
int x=c-dp[m];
if(x>=0){
cout<<x;
}
else{
cout<<"Impossible";
}
return 0;
}
F. 布置房间
题目描述
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过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(<32000)表示总钱数,m(<60)为希望购买物品的个数。)
从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数
v w q
(其中v表示该物品的价格(v<10000),w表示该物品的重要度(1~5),q表示该物品是主件还是附件。如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)
输出格式
只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000)
样例输入
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
样例输出
2200
时空限制
1s,512M
#include<bits/stdc++.h>
using namespace std;
int n,m,f[40000],g[40000];
struct ff{
int p,v,t;
}a[100];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a[i].p,&a[i].v,&a[i].t);
a[i].v*=a[i].p;
}
for(int i=1;i<=m;i++){
if(!a[i].t){
for(int j=1;j<a[i].p;j++){
g[j]=0;
}
for(int j=a[i].p;j<=n;j++){
g[j]=f[j-a[i].p]+a[i].v;
}
for(int j=1;j<=m;j++){
if(a[j].t==i){
for(int k=n;k>=a[i].p+a[j].p;k--){
g[k]=max(g[k],g[k-a[j].p]+a[j].v);
}
}
}
for(int j=a[i].p;j<=n;j++){
f[j]=max(f[j],g[j]);
}
}
}
cout<<f[n];
return 0;
}