经验值:1600 时间限制:1000毫秒 内存限制:128MB
题目描述 Description
有一批共n个集装箱要装上艘载重量为c的轮船,其中集装箱i的重量为wi。找出一种最优装载方案,将轮船尽可能装满,即在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船。
输入描述 Input Description
第一行有2个正整数n和c。n是集装箱数,c是轮船的载重量。接下来的1行中有n个正整数,表示集装箱的重量。
输出描述 Output Description
计算出的最大装载重量
样例输入 Sample Input
5 10 7 2 6 5 4
样例输出 Sample Output
10
数据范围及提示 Data Size & Hint
n<=40,c<=1000
错误代码 TLE 37分:
#include<bits/stdc++.h>
using namespace std;
int n,v,a[45],mx;
bool b[45];
void dfs(int x){
if(x==n+1){
int s=0;
for(int i=1;i<=x;i++){
if(b[i]){
// cout<<a[i]<<' ';
s+=a[i];
}
}
// cout<<endl;
if(s<=v){
mx=max(mx,s);
}
return ;
}
b[x]=1;
dfs(x+1);
b[x]=0;
dfs(x+1);
}
int main(){
cin>>n>>v;
for(int i=1;i<=n;i++){
cin>>a[i];
}
dfs(1);
cout<<mx;
return 0;
}
用了搜索,结果TLE,求大佬指点!!!
熊潇然在2022-11-06 20:48:09追加了内容
为了方便大佬们复制代码,我就用了代码分享
熊潇然在2022-11-06 21:17:23追加了内容
@姜宇轩 emmm......不会
#include<bits/stdc++.h>
using namespace std;
int n,v,a[45],mx;
bool b[45][45];
void dfs(int x,int u){
if(b[i][j]!=-1){
//返回b[i][j]
//return b[i][j]???
}
//听得好绕,递归并不怎么会,不会写
}
int main(){
cin>>n>>v;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
b[i][j]=-1;
}
}
dfs(1,1);
cout<<mx;
return 0;
}
熊潇然在2022-11-07 09:33:10追加了内容
@姜宇轩 样例都没过,应该是我哪里理解错了
#include<bits/stdc++.h>
using namespace std;
int n,v,a[45];
int b[45][1005];
int f(int i,int j){
if(b[i][j]!=-1){
return b[i][j];
}
if(i==0){
return 0;
}
if(a[i]<=j){
b[i][j]=f(i-1,j-a[i])+a[i];
}else{
b[i][j]=f(i-1,j);
}
}
int main(){
cin>>n>>v;
for(int i=1;i<=n;i++){
cin>>a[i];
}
memset(b,-1,sizeof(b));
cout<<f(n,v);
return 0;
}
用一下记忆化搜索,其实就是递归
1.状态:f(i,j)在前i个物品中选一些物品,保证总重量不会超过j,求能装下的最大重量
2.边界:i==0 在前0个物品中选是不行的,最大重量是0
3.目标:在前n个物品中选择一些物品总重不超过v,f(n,v)
4.递归关系
需要考虑第i件物品选不选
选的话,得到了a[i]点重量,在前i-1件物品中选择的时候总重不能超过j-a[i]
f(i-1,j-a[i])+a[i]
不选的话 一点重量都获得不了,在前i-1件物品中选择的时候总重不能超过j
f(i-1,j)
只要当前物品的重量<=j就可以选
记忆化搜索就是把每次求出的答案存起来,这样要用的时候就不用再求一遍了(防止TLE)
定义一个二维数组b对应的是函数当中的i和j
为了区分存没存值,可以用memset把数组的初值赋为-1,每次调用函数时在开头判断这个函数f(i,j)有没有算过,如果算过,则b[i][j]肯定不为-1,直接返回b[i][j]就可以了。
希望你能做对。
@熊潇然 其实就是递归
每次执行递归函数的开头判断当前的f(i,j)有没有算过,也就是if(b[i][j]!=-1),如果不是-1,说明算过,直接返回b[i][j]就行:return b[i][j](前提是你的函数不能定义成void类型,因为b[i][j]是整数类型)
然后判断递归的边界:如果i==0,在前0个物品中选是选不出重量的,最大重量就是0,直接返回0
接着判断当前元素(a[i])能不能选,表示为a[i]<=j,如果a[i]<=j则能选,执行f(i-1,j-a[i])+a[i]
如果a[i]>j则不能选,执行f(i-1,j)
对照着我昨天写的再想想,把你写的代码发出来
还有,不用双重循环定为-1,用memset函数,b数组也不能是bool类型,数组定义的也小了,求得是在前n个物品中选择一些总重不超过c,应该定义成b[n+5][c+5],主函数里要写f(n,c)。
memset(数组名,要赋的值,sizeof(数组名));
要赋的值只能是-1,0,0x3f3f3f3f,-0x3f3f3f3f。
