题目1462:两船载物问题
-
题目描述:
-
给定n个物品的重量和两艘载重量分别为c1和c2的船,问能否用这两艘船装下所有的物品。
-
输入:
-
输入包含多组测试数据,每组测试数据由若干行数据组成。
第一行为三个整数,n c1 c2,(1 <= n <= 100),(1<=c1,c2<=5000)。
接下去n行,每行一个整数,代表每个物品的重量(重量大小不大于100)。
-
输出:
-
对于每组测试数据,若只使用这两艘船可以装下所有的物品,输出YES。
否则输出NO。
-
样例输入:
-
3 5 8 6 3 3 3 5 8 5 3 4
-
样例输出:
-
NO YES
算法分析
第一种编程方法
这道题是典型的背包问题,我们可以把问题转为:
在一条船上尽可能多的放置货物,然后看剩下的货物另外一条船能否装下。
dp[j]表示容量为j的船只 所能装的最多的货物量,每次考虑一个货物,更新dp[j]
for(int j = smallBoat; j>=boatw[i]; j--){
dp[j] = std::max(dp[j],boatw[i]+dp[j-boatw[i]]);
注意更新dp[j]一定是从高到低更新。原因可参考题目1209:最小邮票数
类似的题目有题目1364:v字仇杀队 题 题目1455:珍惜现在,感恩生活
第二种编程方法
我们仿照题目1420:Jobdu MM分水果 用另外一种方式实现求船的最大载重。
也就是 在给定船只大小smallboat,和货物重量的情况下,哪些实际装载量可以实现。
booldp[j] 为真表示可以实现j个装载量,更新过程如下
for(int j = smallBoat; j>=boatw[i]; j--){
booldp[j] = booldp[j] || booldp[j-boatw[i]];
}
需要注意的是 booldp[0] 一定要设置为true,因为在船上一个货物都不放,就是0,booldp[0]=true.
算法的时间复杂度与smallboat有关,所以如果两只船只重量相差很大的话,对小船求最大载重可以减少程序时间。
其它相似问题
普通背包问题
题目1364:v字仇杀队
题目1462:两船载物问题
题目1455:珍惜现在,感恩生活
题目1209:最小邮票数
题目1420:Jobdu MM分水果
项目安排类题目
题目1499:项目安排
题目1463:招聘会
题目1434:今年暑假不AC
资源无限求最大值的题目。
题目1494:Dota
源程序
//============================================================================
// Name : judo1462.cpp
// Author : wdy
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
//similar to 1420
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
//::vector<int> wts;
int boatw[101]={0};
int dp[5001]={0};
int sumw = 0;
void init(int n){
sumw = 0;
for(int i = 1;i<n+1;i++){
scanf("%d",boatw+i);
sumw+=boatw[i];
}
}
void judge(int n,int smallBoat,int bigBoat){
if(sumw > smallBoat+bigBoat){
printf("NO\n");
return;
}
// *dp = new int[boat1 + 1];
memset(dp,0,(smallBoat+1)*sizeof(int));
for(int i = 1;i<n+1;i++){
for(int j = smallBoat; j>=boatw[i]; j--){
dp[j] = std::max(dp[j],boatw[i]+dp[j-boatw[i]]);
}
}
if(sumw - dp[smallBoat] <=bigBoat ){
printf("YES\n");
}else
printf("NO\n");
}
void judgenew(int n,int smallBoat,int bigBoat){//using bool
if(sumw > smallBoat+bigBoat){
printf("NO\n");
return;
}
bool *booldp = new bool[smallBoat + 1];
memset(booldp,0,(smallBoat+1)*sizeof(bool));
booldp[0] = true;//Attention must be true
for(int i = 1;i<n+1;i++){
for(int j = smallBoat; j>=boatw[i]; j--){
booldp[j] = booldp[j] || booldp[j-boatw[i]];
}
}
for(int i = smallBoat;i>=0;i--){
if(booldp[i]){
if(sumw - i<=bigBoat)
printf("YES\n");
else
printf("NO\n");
return;
}
}
}
void judo(){
int n;
int boat1;
int boat2;
while(scanf("%d %d %d",&n,&boat1,&boat2)!=EOF){
init(n);
if(boat1<boat2)
judgenew(n,boat1,boat2);
else
judgenew(n,boat2,boat1);
}
}
int main() {
judo();
return 0;
}
/**************************************************************
Problem: 1462
User: KES
Language: C++
Result: Accepted
Time:10 ms
Memory:1540 kb
****************************************************************/
题目1364:v字仇杀队
题目1462:两船载物问题
题目1455:珍惜现在,感恩生活
题目1209:最小邮票数
题目1420:Jobdu MM分水果
项目安排类题目
题目1499:项目安排
题目1463:招聘会
题目1434:今年暑假不AC
资源无限求最大值的题目。
题目1494:Dota