贪心算法_乘船问题

题目描述:

描述 
进行一次独木舟的旅行活动,独木舟可以在港口租到,并且之间没有区别。一条独木舟最多只能乘坐两个人,且乘客的总重量不能超过独木舟的最大承载量。我们要尽量减少这次活动中的花销,所以要找出可以安置所有旅客的最少的独木舟条数。现在请写一个程序,读入独木舟的最大承载量、旅客数目和每位旅客的重量。根据给出的规则,计算要安置所有旅客必须的最少的独木舟条数,并输出结果。
输入 
第一行输入s,表示测试数据的组数; 
每组数据的第一行包括两个整数w,n,80<=w<=200,1<=n<=300,w为一条独木舟的最大承载量,n为人数; 
接下来的一组数据为每个人的重量(不能大于船的承载量); 
输出 
每组人数所需要的最少独木舟的条数。
样例输入 

85 6 
5 84 85 80 84 83 
90 3 
90 45 60 
100 5 
50 50 90 40 60
样例输出 


3

今天刚参加完学校的程序设计大赛。很遗憾没有把这个题目给做完,期间机器出了点问题,而且运行的myeclipse8.5有点卡。

但是回来之后我虑了一下思路:下面说一下我自己的思路,我自己用的递归方法,边调试边修改出来的。

1、设置相关的变量。

	static int[] MaxWeight = null; //最大的载重量
	static int s = 0;
        static int n = 0;// 人数
	static int[] BoardNum = null; // 船的数量
	static int[][] PW = null;   //所有人的重量
	static int[] PW1 = null;	//一次测试人的重量
	static int Weights = 0;//把重量都加起来


2、对数据进行排序,先从轻的人开始计算,如果不满足条件(目前的重量和 大于 或者 等于  船的最大载重量)就继续算Weights重量的和。如果目前的总重量Weights和 等于了 船的最大载重量MaxWeight,就将BoardNum++;如果目前的总重量Weights大于了MaxWeight,也将BoardNum++,同时(关键的问题了)将列数据 j–(假设你的MaxWeight为 90,且所有人的重量已经在PW二维数组中排好序了,现在有3个人的体重为:45 60 90,45+60=105,满足要求,BoradNum++ ,然后进行下一次的判断,判断 60和 90的人 的重量,如果你不把列数据–的话,就不能再用到60斤的这个人了,相当于把它给扔了,这里仔细体会一下)。然后进行下一次递归将j+1;就罗嗦这么多了,具体的看正确的代码。

在我的代码里面觉得重要的是,2个变量的声明,一个是PW,所有人的重量都保存在这里,然后一个是PW1,保存测试一次的数据,然后用copyOf到PW数组里面去。为什么要这样做?看我下面的注释(我考试的时候问题就出在了这里,测试一次的结果是正确的,但是测试输入3次,结果就是错误的,前面2次是0,最后一次是3),下面看我考试的时候的(错误)算法。

public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		s = input.nextInt(); //测试数据的组数
		MaxWeight = new int[s]; //开辟相应的数组,保存每只船的最大重量
		BoardNum = new int[s]; //船的数量
		for (int i = 0; i < s; i++) {
			MaxWeight[i] = input.nextInt();
			n = input.nextInt(); //人数
			PW = new int[s][n];  //开辟s组,n个人的数组。    //问题就出现在这里的。不知道大家看到了没有,如果s为1,也就
//测试一组数据的时候,这里的new[s][n]只运行了一次,没问题,但是当你s为3的时候,会new3个,每次会把数据给清0,所以我在下面想了一个办法
			for(int j = 0;j < n; j++) {
				PW[i][j] = input.nextInt();
			}
		Arrays.sort(PW[i]);
		Fun(PW, 0, 0);
		for (int i = 0; i < s; i++)
			System.out.println(BoardNum[i]);
}


下面请看正确的代码:

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

public class 运输船的数量 {
	static int s = 0;
	static int[] MaxWeight = null; // 最大的载重量
	static int n = 0;// 人数
	static int[] BoardNum = null; // 船的数量
	static int[][] PW = null; // 所有人的重量
	static int[] PW1 = null; // 一次测试人的重量
	static int Weights = 0;

	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		s = input.nextInt();
		MaxWeight = new int[s];
		BoardNum = new int[s];
		PW = new int[s][];   //初始化所有的人的重量数组
		for (int i = 0; i < s; i++) {
			MaxWeight[i] = input.nextInt();
			n = input.nextInt();
			PW1 = new int[n];   
			for (int j = 0; j < n; j++) {
				PW1[j] = input.nextInt();
			}
			PW[i] = Arrays.copyOf(PW1, PW1.length); //将数据copy到PW中,这样就避免了被清零
			Arrays.sort(PW[i]);
		}
		Fun(PW, 0, 0);  //调用递归
		for (int i = 0; i < s; i++)
			System.out.println(BoardNum[i]);
	}

	public static void Fun(int[][] Pw, int i, int j) {
		if (j == Pw[i].length) { //如果一列已经遍历完了,就对列置零,行进行+1操作
			j = 0;
			if (i < s ) {   //不超过s-1 包括s-1
				if ((i + 1) < s) //因为下面要进行i+1,进行下一行的遍历,这里避免出界
					Fun(Pw, i + 1, j);
			} else {
				return;
			}
		} else {
			Weights += Pw[i][j];       //累加重量,等于最大重量和大于最大重量处理情况不同
			if (Weights == MaxWeight[i]) { //等于的话,就直接进行下一列的操作
				BoardNum[i]++;
				Weights = 0;
			} else if (Weights > MaxWeight[i]) { //大于的话,在进行下一列操作之前还有对列///进行回滚,j--,要用到上一个数
				BoardNum[i]++;
				Weights = 0;
				j--;
			}
			Fun(Pw, i, j + 1);  //进行下一列的操作
		}
	}
}
    原文作者:贪心算法
    原文地址: https://blog.csdn.net/q361239731/article/details/50018259
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞