题解|贪心算法快速过桥

快速过桥

UVA-10037

[问题描述]
n个人的队伍想在晚上通过一座大桥。

任何时间最多有2人通过,每组必须有一个手电筒。

很可怜,这n个人只有一个手电筒可用,因此必须合理地安排,让手电筒能回到另一端,这样才能让更多人通过大桥。

每个人有不同的速度,编组后,一个组的速度等于慢的那个人的速度。

你的任务是实现一种策略,让所有人在最短时间内通过。

[输入]
第一行是一个单独的数字,代表测试案例的个数;随后是一个空行。后面每两个输入之间都有一个空行。

每个测试案例的第一行是n的值,随后n行是每个人单独通过大桥的时间。人数≤1000,时间≤100s

【输出】
对每个案例,首行是n个人通过的时间。

随后是你的通过和返回次序,每一行是一个或者两个整数,对应着人(通过时间代表人)。返回也要占一行。

虽然不同的人可能有相同的速度,但这没有影响(看做一种人就好了)。

注意方向,意思就是说返回情况也要占一行。

多种方案都是最短时间的,任选其一皆可。

案例之间空行分界。

【样例输入】
1

4
1
2
5
10

【样例输出】
17
1 2
1
5 10
2
1 2

【解释】
17 秒
1 2 2秒
1 1秒
5 10 10秒
2 2秒
1 2 2秒

源代码

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

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int m = sc.nextInt();
		sc.nextLine();
		for (int i = 0; i < m; i++) {
			int n = sc.nextInt();
			int[] data = new int[n];
			for (int j = 0; j < data.length; j++) {
				data[j] = sc.nextInt();
			}
			Arrays.sort(data);
			TimeAndPath tap = new TimeAndPath();
			solution(data, tap, 0, data.length - 1);
			tap.print();
			if (i != m - 1) {
				System.out.println();
			}
		}
	}

	private static class TimeAndPath {
		LinkedList<String> list = new LinkedList<>();
		private int time = 0;

		private void print() {
			System.out.println(time);
			for (String s : list) {
				System.out.println(s);
			}
		}
	}

	// 递归函数,做出最佳决策,将begin到end个人的过桥路径和过桥时间存储再tap中
	private static void solution(int[] data, TimeAndPath tap, int begin, int end) {
		int A = data[begin];
		if (begin == end) {
			tap.time += A;
			tap.list.add(A + "");
			return;
		}
		int Z = data[end];
		if (begin + 1 == end) {
			tap.time += Z;
			tap.list.add(A + " " + Z);
			return;
		}
		int Y = data[end - 1];
		if (begin + 2 == end) {
			tap.time += A + Y + Z;
			tap.list.add(A + " " + Z);
			tap.list.add(A + "");
			tap.list.add(A + " " + Y);
			return;
		}
		int B = data[begin + 1];
		int timeOfPlanA = B + A + Z + B;
		int timeOfPlanB = Z + A + Y + A;
		// 做出最末尾两个人过桥的最佳决策
		if (timeOfPlanA < timeOfPlanB) {
			tap.time += timeOfPlanA;
			tap.list.add(A + " " + B);
			tap.list.add(A + "");
			tap.list.add(Y + " " + Z);
			tap.list.add(B + "");
		} else {
			tap.time += timeOfPlanB;
			tap.list.add(A + " " + Z);
			tap.list.add(A + "");
			tap.list.add(A + " " + Y);
			tap.list.add(A + "");
		}
		solution(data, tap, begin, end - 2);
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值