N个人过桥(类似N个人过河)

题目描述

n个人要过一座桥,只是在漆黑的夜里,没有火把显然是不行的。但是这n个人只有一个火把,并且这座桥每次最多只能通过两个人。
每个人的速度不同,若两人组队,队伍速度等于较慢一人的速度。你要做的是计算这n个人全部通过这座桥的最少时间。

输入

多组输入。每组数据的第一行是输入一个n,代表有n(1 <= n && n <= 500)个人,接下来的n个整数,代表着每个人穿过这座桥所需要的时间。

输出

输出一个整数,代表最优策略所需时间sum

示例输入

4
1
10
5
2

示例输出

17

提示

假设人员编号按输入顺序从1n,首先编号为1,4的人通过,编号为1的回来送火把,然后编号为2,3组队通过,编号为4的回来送火把,编号为1,4通过,结束。

sum = 2 + 1 + 10 + 2 + 2 = 17。

思路:

把每个人过桥的时间排序,每次都使用过桥时间最短的两个人把过桥时间最长的两个人送过桥。假设left = [a,b,..]表示桥左边的人,right = [a,b,...]表示桥右边的人。
假设时间最短的两个人的过桥时间为a,b,时间最长的两个人为x,y,其中a < b < x < y则过桥方式有两个思路:
方式一:
让这四个人当中时间最短的人护送时间最长的两个人过河,状态为:

状态                                                                时间
left = [b, x]                  right = [a, y]                       y
left = [a, b, x]               right = [y]                          a
left = [b]                     right = [a, x, y]                    x
left = [a, b]                  right = [x, y]                       a

// 总时间
sum += y + a + x + a = 2 * a + x + y

方式二:
让四个人当中时间最长的人一起过河,则节约了次长的人的时间,状态为

状态                                                                时间
left = [x, y]                  right = [a, b]                       b
left = [a, x, y]               right = [b]                          a
left = [a]                     right = [b, x, y]                    y
left = [a, b]                  right = [x, y]                       b

// 总时间
sum += b + a + y + b = 2 * b + a + y

由方式一和方式二可知,在每次使用时间最短的人把时间最长的人运过河的时候,需要进行比较,看看选择方式一还是方式二更加节约时间,若方式一更快,则有2 * a + x + y < 2 * b + a + y,化简得2 * b > a + x
如果2 * b > a + x,则有sum += 2 * a + x + y
如果2 * b <= a + x,则有sum += 2 * b + a + y

还没有过河的人数小于4的时候,考虑n=1,2,3的情况:
n = 1时,直接过河,时间为a;
n = 2时,直接两人一起过河,时间为b;
n=3时,假设人为a, b, x,则有:

状态                                                                时间
left = [b]                  right = [a, x]                          x
left = [a, b]               right = [x]                             a
left = []                     right = [a, b, x]                     b

// 总时间
sum = a + b + x

过河时间为a + b + x

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
 
int main()
{
    int i, j, n, num[1000], a, b, x, y;
    while(cin >> n)
    {
        for(i=0; i<n; i++) {
            cin >> num[i];
        }
        sort(num, num + n);
        int sum = 0;
        while(n >= 4)
        {
            a = num[0];
            b = num[1];
            x = num[n - 2];
            y = num[n - 1];
            if(2 * b < a + x)
            {
                sum += 2 * b + a + y;
                n -= 2;
            }
            else
            {
                sum += a * 2 + x + y;
                n-=2;
            }
        }
        if(n == 3) {
        	sum += num[0] + num[1] + num[2];
        }
        else if (n<=2) {
        	sum+=num[n-1];
        }
        cout<< sum <<endl;
    }
    return 0;
} 
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值