POJ1700 经典过河问题(贪心)通俗易懂

快速过河问题:

题目大意:有n个人要过一条河,每个人过河都需要一个时间ai,有一艘船,每次过河只能最多装两个人。两个人划船过河所需的时间都取决于过河时间长的那个人。比如,A,B两人过河所需时间分别为a,b,那么,他们成一条船过河所需的时间为:max{a,b}。现在让你安排一个过河方案,让所有人用最短的时间全部过河。此题在POJ1700上,另外洛谷P1809题类似。

既然搜了这个问题,必然懂了题意

有两种解适用不同的情况。人数为1、2、3时不做描述,很容易得出最优解。当人数为4的时候:

方案一:每次都是最快的回来带人。

方案二:最快的两个人先去,回来其中一个人(谁都行),然后最慢的两个人去(这样算最慢的时间,次慢的不算),再回来另一个人(两个最快的人还没去),最后两个最快的去。

当人数大于4的时候,我想了根据想不通,怎么送?
我漏了一个很重要的方面导致我想不通,两种最优解,并不是用同一个方法求出最优解!是根据最优的方法,逐步求出。将求运送四个人的方法简单变通一下,每次只两种方法运送最慢的两个人,求这个最优解:

方案一:总是用最快的带人,带“次快的-次次快……次次慢-次慢-最慢”,等于“最慢-次慢-……-次次快-次快”。(每次都回来最快,所以先带谁都一样),就让最快先送最慢的两个人,时间就是:最慢和最快去,最快回,次慢最快去,最快回(最快要回来,因为还有人没过去啊,最快回来两次)= 最快*2+最慢+次慢

方案二:根据上面方案二的描述,计算的时间是:最慢+最快+次快*2(次快和最快去的,算次快的,次快还要回来,一共两次)

根据两种方案送最慢的两个人。找出用时最短的。然后求剩下没过河的人,因为送过去两个人嘛,没过河的就减去2,这就会产生两种结果:剩下2个人和剩下3个人。正好剩下两个人,时间就是最慢的那个人的时间;正好三个人,最快的办法就是用方案一,最快的带那两个人,即:三个人的时间相加。

理解这个题,参考的文章:

https://blog.csdn.net/qq_36306833/article/details/68941731

很多人用动规,实现的证明,嗯,我不会,只是通俗易懂的明白了这个贪心的奇妙之处。这个动规的证明,去洛谷看题解吧
代码:

import java.util.Arrays;
import java.util.Scanner;

public class 过河 {

//	有n个人,第i个人重量为wi。每艘船的最大载重量均为C,且最多只能乘两个人。用最少的船装载所有人。
//
//	 贪心策略:考虑最轻的人i,如果每个人都无法和他一起坐船(重量和超过C),则唯一的方案是每个人坐一艘
//	 否则,他应该选择能和他一起坐船的人中最重的一个j
	public static void main(String[] args) {
		int[] nums = {1,2,2,2,10};
//		Scanner sc = new Scanner(System.in);
//		int n = sc.nextInt();
//		int[] nums = new int[n];
//		for (int i = 0; i < nums.length; i++) {
//			nums[i] = sc.nextInt();
//		}

		Arrays.sort(nums);
		System.out.println(t1(nums));

	}

	static int t1(int[] nums) {
		int s = 0;
		int len = nums.length;

		while (true) {
			if (len == 1)
				return nums[0];
			if (len == 2)
				return s + Math.max(nums[0], nums[1]);
			if (len == 3) {
				return s + nums[0] + nums[1] + nums[2];
			}
			int s1 = nums[0] + nums[0] + nums[len - 1] + nums[len - 2]; // 求方案一的时间
			int s2 = nums[0] + nums[1] + nums[1] + nums[len - 1]; // 第二种
//			System.out.println(s1+"  "+s2);
			len -= 2;
			s += Math.min(s1, s2);
		}

	}
}

posted on 2021-04-15 15:37  寄居の友人c  阅读(619)  评论(0编辑  收藏  举报