问题标题: 1049   装载问题

0
0
已解决
熊潇然
熊潇然
初级启示者
初级启示者

1049   装载问题

经验值: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;
}
 

 


0
已采纳
姜宇轩
姜宇轩
中级天翼
中级天翼

@熊潇然 13行15行是返回某个值,加个return,还有13行改成max(f(i-1,j-a[i])+a[i],f(i-1,j))。

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]就可以了。

希望你能做对。

0
0
姜宇轩
姜宇轩
中级天翼
中级天翼

@熊潇然 其实就是递归

每次执行递归函数的开头判断当前的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。

 

 

 

 

0
0
0
我要回答