题目来源:http://www.tsinsen.com/A1133
最近北京大学因为高考原因OJ登不上了,poj和百练都登不上,改在清华的清橙OJ上做题吧
那么问题来了,清华会不会也要高考阅卷呢?
A1133. 装箱问题
时间限制:1.0s 内存限制:256.0MB
试题来源
NOIP2001 普及组
问题描述
有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入格式
第一行为一个整数,表示箱子容量;
第二行为一个整数,表示有n个物品;
接下来n行,每行一个整数表示这n个物品的各自体积。
输出格式
一个整数,表示箱子剩余空间。
样例输入
24
6
8
3
12
7
9
7
样例输出
0
-----------------------------------------------------
解题思路
0-1背包
dp[v][n] = max( dp[v][n-1], dp[v-a[i]][n-1]+a[i]), v>=a[i]
= dp[v][n-1], v<a[i]
简化为一维数组 dp[v] = max(dp[v], dp[v-a[i]]+a[i])
注意用一维数组时要从v到a[i]倒着遍历,否则第i次的dp结果会覆盖第i-1次的dp结果
-----------------------------------------------------
代码
二维dp
#include<iostream> #include<fstream> using namespace std; int dp[20002][35] = {}; int a[35] = {}; int main() { #ifndef ONLINE_JUDGE ifstream fin("0206_8785.txt"); int v,n,i,j; fin >> v >> n; for (i=1; i<=n; i++) { fin >> a[i]; } fin.close(); for (i=1; i<=n; i++) { for (j=v; j>=a[i]; j--) { dp[j][i] = max(dp[j-a[i]][i-1]+a[i], dp[j][i-1]); } for (j=a[i]-1; j>=0; j--) { dp[j][i] = dp[j][i-1]; } } cout << v-dp[v][n]; return 0; #endif #ifdef ONLINE_JUDGE int v,n,i,j; cin >> v >> n; for (i=1; i<=n; i++) { cin >> a[i]; } for (i=1; i<=n; i++) { for (j=v; j>=a[i]; j--) { dp[j][i] = max(dp[j-a[i]][i-1]+a[i], dp[j][i-1]); } for (j=a[i]-1; j>=0; j--) { dp[j][i] = dp[j][i-1]; } } cout << v-dp[v][n]; return 0; #endif }
一维dp
#include<iostream> #include<fstream> using namespace std; int dp[20002] = {}; int a[31] = {}; int main() { #ifndef online_judge ifstream fin("0206_8785.txt"); int v,n,i,j; fin >> v >> n; for (i=0; i<n; i++) { fin >> a[i]; } fin.close(); for (i=0; i<n; i++) { for (j=v; j>=a[i]; j--) // 倒着遍历,防止第i次循环的结果覆盖第i-1次的结果 { dp[j] = max(dp[j-a[i]]+a[i], dp[j]); } } cout << v-dp[v]; return 0; #endif #ifdef online_judge int v,n,i,j; cin >> v >> n; for (i=0; i<n; i++) { cin >> a[i]; } for (i=0; i<n; i++) { for (j=v; j>=a[i]; j--) { dp[j] = max(dp[j-a[i]]+a[i], dp[j]); } } cout << v-dp[v]; return 0; #endif }