P1809 过河问题【解析】

有一类贪心问题具有一定的迷惑性,大多数同学初步思考时会很快得到一种‘看上去很正确’的贪心策略,但是对于大部分贪心问题不能贸然得出结论。我们可以尝试构造一些反例推翻该策略。但是,即使该策略被推翻了,也不一定说明它完全错误,还有可能是在不同条件下贪心策略不同,此时需要分类讨论。因此,在解决贪心问题时,需要我们使用“构造方法、反例验证、打表观察、数学推导”等多种方式结合、多次尝试后,才能最终得到正确的方法。

例如过河问题
有四个人要从 A 点坐一条船过河到 B 点,船一开始在 A 点。该船一次最多可坐两个人。 已知这四个人中每个人独自坐船的过河时间分别为 1,2,4,8,且两个人坐船的过河时间为两人独自过河时间的较大者。则最短( )时间可以让四个人都过河到 B 点(包括从 B 点把船开回 A 点的时间)。

A. 14
B. 15
C. 16
D. 17

【解析】

深入思考发现每次过河船只能承受两个人,且返回还需要一个人折返的时间,因此折返的工作最好交给时间最短的人和次最短的人去做,尽量减少回程时间,使去程贡献最大。由此想到另外一种贪心策略:首先最快和次快的人先过河,最快的人返回,然后最慢与次慢的人再过河,次快的人返回,最后最快和次快的人过河。

那么进入正题,我们来看一下洛古的P1809 过河问题

过河问题

题目描述

有一个大晴天,Oliver 与同学们一共 N N N 人出游,他们走到一条河的东岸边,想要过河到西岸。而东岸边有一条小船。

船太小了,一次只能乘坐两人。每个人都有一个渡河时间 T T T,船划到对岸的时间等于船上渡河时间较长的人所用时间。

现在已知 N N N 个人的渡河时间 T T T,Oliver 想要你告诉他,他们最少要花费多少时间,才能使所有人都过河。

注意,只有船在东岸(西岸)的人才能坐上船划到对岸。

输入格式

输入文件第一行为人数 N N N,以下有 N N N 行,每行一个数。

i + 1 i+1 i+1 行的数为第 i i i 个人的渡河时间。

输出格式

输出文件仅包含一个数,表示所有人都渡过河的最少渡河时间。

样例 #1

样例输入 #1

4 6 7 10 15

样例输出 #1

42

提示

数据范围

对于 40 % 40\% 40% 的数据满足 N ≤ 8 N\le8 N8

对于 100 % 100\% 100% 的数据满足 N ≤ 100000 N\le100000 N100000

样例解释

  • 初始:东岸 { 1 , 2 , 3 , 4 } \{1,2,3,4\} {1,2,3,4},西岸 { } \{\} {}
  • 第一次:东岸 { 3 , 4 } \{3,4\} {3,4},西岸 { 1 , 2 } \{1,2\} {1,2},时间 7 7 7
  • 第二次:东岸 { 1 , 3 , 4 } \{1,3,4\} {1,3,4},西岸 { 2 } \{2\} {2},时间 6 6 6
  • 第三次:东岸 { 1 } \{1\} {1},西岸 { 2 , 3 , 4 } \{2,3,4\} {2,3,4},时间 15 15 15
  • 第四次:东岸 { 1 , 2 } \{1,2\} {1,2},西岸 { 3 , 4 } \{3,4\} {3,4} 时间 7 7 7
  • 第五次:东岸 { } \{\} {},西岸 { 1 , 2 , 3 , 4 } \{1,2,3,4\} {1,2,3,4} 时间 7 7 7

所以总时间为 7 + 6 + 15 + 7 + 7 = 42 7+6+15+7+7=42 7+6+15+7+7=42,没有比这个更优的方案。

依据上面的分析思想可写出完整代码如下:

#include<bits/stdc++.h>
using namespace std;
int a[100005];
int main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	int sum=0;
	while(n){
		if(n==1){
			sum+=a[1];
			n=0;
		}
		else if(n==2){
			sum+=a[2];
			n=0;
		}else if(n==3){
			sum+=a[1]+a[2]+a[3];
			n=0;
		}else if(n>=4){
			if(2*a[2]>a[1]+a[n-1]){
				sum+=(a[n-1]+a[n])+2*a[1];n-=2;
			}else {
				sum+=a[2]+a[1]+a[n]+a[2];n-=2;
			}
		}
		
		
		
	}
	cout<<sum;
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小芒果_01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值