乘船问题

乘船问题

有n个人,第i个人重量wi,每艘船的载重量均为C,最多可乘2人。求用多少船装载所有人的方案。
贪心策略:最轻的人与最重的人配对。

题目

有n个人,第i个人重量为wi,每艘船的最大载重量为C,且最多只能乘两个人。用最少的船装载所有人。题目保证有解。
【样例输入1】
6
5 84 85 80 84 83
85
【样例输出1】
5
【样例输入2】
3
90 45 60
90
【样例输出2】
3
【样例输入3】
5
50 50 90 40 60
100
【样例输出3】
3

分析

从最轻的人i开始考虑:如果每个人都无法和他一起坐船,则唯一的方法就是每人坐一艘船;否则,他应该选择能和他一起坐船的人中最重的一个j。这样的方法是贪心的,因为它只是让“眼前的浪费”最少。
可以用反证法证明此策略的正确性:
(1)i不与任何人同船。如果将j拉来与其同船,使用的船数<=原来的船数;
(2)i与k同船。由贪心策略,因为此时i是最轻的,j是与i匹配的人中最重的,所以w[k]<=w[j],则j加入其它船可能会使其它船超重,用的船数会变多;
综上,说明这样的贪心法不会丢失最优解。
故解题步骤:(循环过程)
(1)将所有人的重量进行排序;
(2)从当前最轻的人i开始考虑,找能跟其坐一艘船的最重的人j;
(3)比最重的人j都重的人都单独坐一个船;
需要特别注意的是:循环过程中若发现i=j,表明仅剩1人待安排,此时这个人自己一船。

代码

#include <iostream>  
#include <algorithm>  
using namespace std;  
const int maxn=1005;  
int n,C;     //n个人 船最大载重量C  
int ans=0;   //使用的最少船数   
int w[maxn]; //n个人的重量   
int main()  
{  
    int i,j;   
    cin>>n;  
    for(i=0;i<n;i++)  
        cin>>w[i];  
    cin>>C;  //预处理:n个人按重量递增排序   
 sort(w,w+n); //i.j分别用来标记待安排的最轻的人和最重的人   
    i=0,j=n-1;   //当还有人待安排时,循环   
    while(i<=j)  
    {  
 //待安排的人中最轻的人和最重的人重量之和超过船的最大载重量  
        //或者仅剩1人待安排时,j单独一船   
        if(i!=j && w[i]+w[j]>C)  
        {  
            ans++;  
            j--;  
        }   //其它情况:i和j两人同船   
        else  
        {  
            ans++;  
            i++;  
            j--;  
        }  
    }  
    cout<<ans<<endl;  
    return 0;  
} 
  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯算法是一种求解排列、组合等组合优化问题的常用算法,可以用来求解乘船问题。具体算法流程如下: 1.将人按体重从小到大排序。 2.定义一个数组used记录每个人是否已经被乘船。 3.从第一个人开始遍历,依次把每个人加入船中,直到达到船的最大载重或者船已满两人为止。 4.如果船已满两人,那么尝试把船中的人卸载,并尝试把下一个未乘船的人加入船中。 5.如果所有人都已经被乘船,那么记录当前船数,如果当前船数比已知的最小船数要小,则更新最小船数。 6.回溯到上一个状态,尝试下一个人。 下面是Python代码实现: ```python def backtrack(n, w, C): w.sort() # 按体重排序 used = [0] * n # 记录每个人是否已经乘船 min_boat_num = float("inf") # 初始化最小船数为正无穷 def dfs(cur, cur_weight, cur_boat_num): nonlocal min_boat_num if cur_boat_num >= min_boat_num: # 如果当前船数已经大于已知的最小船数,则剪枝 return if cur == n: # 如果所有人都已经乘船,则记录当前船数并更新最小船数 min_boat_num = min(min_boat_num, cur_boat_num) return if not used[cur]: # 如果当前人未乘船 used[cur] = 1 # 标记当前人已乘船 if cur_weight + w[cur] <= C: # 尝试把当前人放入船中 dfs(cur + 1, cur_weight + w[cur], cur_boat_num) for i in range(cur + 1, n): # 尝试把当前人和后面的人放入船中 if not used[i] and cur_weight + w[cur] + w[i] <= C: used[i] = 1 dfs(cur + 1, cur_weight + w[cur] + w[i], cur_boat_num + 1) used[i] = 0 used[cur] = 0 # 回溯到上一个状态 dfs(0, 0, 0) return min_boat_num ``` 在主函数中输入人数n、每个人的体重w和船的最大载重量C,并调用backtrack函数求解最少的船数。 ```python if __name__ == "__main__": n = 6 w = [2, 3, 5, 1, 4, 6] C = 10 min_boat_num = backtrack(n, w, C) print(min_boat_num) ``` 输出结果为2,即最少需要2艘船才能装载所有人。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值