首页 > 试题广场 >

漂流船问题

[编程题]漂流船问题
  • 热度指数:8346 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
公司组织团建活动,到某漂流圣地漂流,现有如下情况:
员工各自体重不一,第 i 个人的体重为 people[i],每艘漂流船可以承载的最大重量为 limit。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。
为节省开支,麻烦帮忙计算出载到每一个人所需的最小船只数(保证每个人都能被船载)。

输入描述:
第一行输入参与漂流的人员对应的体重数组,

第二行输入漂流船承载的最大重量


输出描述:
所需最小船只数
示例1

输入

1 2
3

输出

1

贪心

将人的体重升序排列,划分为“体重<=limit/2”的左半部分和“体重>limit/2”的右半部分。然后双指针求解,L指针指向左半部分最后一个人,R指针指向右半部分第一个人。
  1. 如果两人的体重<=limit就右移右指针,直到people
    [L]无法再与右半部分的人配对,此时能够搞定右边rightSolved个人就表示左边也能搞定rightSolved个人,占用rightSolved条船。然后左指针向左移动rightSolved个位置。
  2. 如果一个右边的人都配对不了,就增加一个左半部分搞不定的人leftNoSolved,左移左指针,直到左指针越界。
此时我们知道左半部分的总人数,被搞定的人数,右半部分搞定的人数。然后我们可以计算左半部分有多少人没船坐,他们可以两人一艘船,再计算右半部分有多少人没船坐,他们只能一人一艘船。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Arrays;

public class Main {
    public static void main(String
[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String
[] strs = br.readLine().split(" ");
        int n = strs.length;
        int
[] people = new int
[n];
        for(int i = 0; i < n; i++){
            people
[i] = Integer.parseInt(strs
[i]);
        }
        Arrays.sort(people);
        int limit = Integer.parseInt(br.readLine());
        int lessR = lowerBound(people, limit >> 1);     // 找到最后一个小于等于limit/2的位置
        int L = lessR;
        if(L == n){
            // 全是小于limit/2的体重,直接两个人一艘船
            System.out.println((n + 1) >> 1);
        }else{
            int R = L + 1;
            int leftNoSolved = 0;      // 左边没搞定的人
            int rightSolved = 0;       // 右边搞定的人
            while(L >= 0){
                while(R < n && people
[L] + people
[R] <= limit){
                    R++;
                    rightSolved++;
                }
                if(rightSolved == 0){
                    // L和右边的人配对一个都搞不定
                    leftNoSolved++;      // 添加一个没搞定的人
                    L--;                 // 左移左指针
                }else{
                    L = Math.max(-1, L - rightSolved);
                }
            }
            int leftAll = lessR + 1;
            int rightUnsolved = n - leftAll - rightSolved;
            System.out.println(rightSolved + ((leftNoSolved + 1) >> 1) + rightUnsolved);
        }
    }
    
    private static int lowerBound(int
[] nums, int target) {
        int left = 0, right = nums.length, index = right;
        while(left < right){
            int mid = left + ((right - left) >> 1);
            if(nums
[mid] > target){
                right = mid - 1;
            }else{
                index = mid;
                left = mid + 1;
            }
        }
        return index;
    }
}

编辑于 2022-01-16 15:48:01 回复(0)
/*
我的想法,先排序,然后开始找同伴
*/
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();
        String[] arr = str.split(" ");
        int[] people = new int[arr.length];
        for(int i = 0;i<arr.length;i++){
            people[i] = Integer.parseInt(arr[i]);
        }
        int limit = input.nextInt();
        
        //先排序
        Arrays.sort(people);
        int count = 0;//船的数量,上船的人这个会加一,他的体重也会被成-1
        for(int i = 0;i<people.length;i++){
            if(people[i]!=-1){//如果这个人没有上船
                int right = people.length-1;
                while(right>i){
                    if(people[right]!=-1){
                        if(people[i]+people[right]<=limit){
                            people[i]=-1;
                            people[right]=-1;
                            count++;
                            break;
                        }
                    }
                    right--;
                }
                if(people[i]!=-1)count++;
            }else
                continue;
        }
        System.out.println(count);
    }
}

发表于 2020-04-20 16:04:35 回复(0)
借鉴了别人的思路
import java.util.*;
public class Main{
    public static int boat(int[] weights,int max){
        Arrays.sort(weights);
        int i=0;
        int j=weights.length-1;
        int num=0;//记录所需船数
        while(i<j){
            if(weights[i]+weights[j]<=max){//配对成功
                num++;//两人给一条船
                i++;
                j--;
            }
            else{//体重超出限制,依次找较轻的
                num++;//胖的单独给一条船
                j--;
            }
        }
        if(i==j) num++;//剩下的那个人给一条船
        return num;
    }
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        String[] str=sc.nextLine().split(" ");
        int[] arr=new int[str.length];
        for(int i=0;i<str.length;i++){
            arr[i]=Integer.parseInt(str[i]);
        }
        int max=sc.nextInt();
        System.out.println(boat(arr,max));
    }
}


发表于 2020-03-27 10:52:14 回复(0)
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

/*公司组织团建活动,到某漂流圣地漂流,现有如下情况:
员工各自体重不一,第 i 个人的体重为 people[i],每艘漂流船可以承载的最大重量为 limit。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。
为节省开支,麻烦帮忙计算出载到每一个人所需的最小船只数(保证每个人都能被船载)。
输入描述:
第一行输入参与漂流的人员对应的体重数组,

第二行输入漂流船承载的最大重量
输出描述:
所需最小船只数*/
//48
public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
        String[] s = sc.nextLine().split(" ");
        int limit = sc.nextInt();
        Arrays.sort(s,new Compare());
        int le = 0,ri = s.length-1;
        int people = s.length,count = 0;
        while(people>0){
        	if(Integer.parseInt(s[le])+Integer.parseInt(s[ri])<=limit){
        		count++;
        		people-=2;
        		le++;
        		ri--;
        	}else if(Integer.parseInt(s[ri])<=limit){
        		count++;
        		people--;
        		ri--;
        	}else{
        		count++;
        		people--;
        		le++;
        	}
        }
        System.out.println(count);
	}
	static class Compare implements Comparator<String> {

		@Override
		public int compare(String o1, String o2) {
			return Integer.parseInt(o1)-Integer.parseInt(o2);
		}
		
	}
}

发表于 2019-09-14 19:36:28 回复(0)
为什么最大体重加最小体重能保证船数最小,有没有大佬能解惑一下?
我的思路是尽量把每艘船承载的体重都接近limit值,哈希表实现
import java.io.*;
import java.util.Map;
import java.util.HashMap;
public class Main{
    public static void main(String[] args) throws Exception{
        BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
        String[] weight=in.readLine().split(" ");
        String limits=in.readLine();
        int n=weight.length;
        if(n==0){
            System.out.println("输入错误");
            return;
        }
        int[] people=new int[n];
        for(int i=0;i<n;++i){
            people[i]=Integer.parseInt(weight[i]);
        }
        int limit=Integer.parseInt(limits);
        //哈希表
        Map<Integer,Integer> map=new HashMap<>();
        int count=0;
        for(int i=0;i<n;++i){
            map.put(people[i],map.getOrDefault(people[i],0)+1);
        }
        for(int i=0;i<n;++i){
            if(map.get(people[i])==0)
                continue;
            if(limit>=people[i]){
                map.put(people[i],map.get(people[i])-1);
                int temp=limit-people[i];
                while(temp>0&&(map.get(temp)==null||map.get(temp)==0)){
                    temp--;
                }
                count++;
                if(temp>0){
                    map.put(temp,map.get(temp)-1);
                }
            }
        }
        System.out.println(count);
    }
}


发表于 2019-08-07 17:37:50 回复(0)
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] peoples = in.nextLine().split(" ");
        int limit = in.nextInt();
        int n = peoples.length;
        int[] p = new int[n];
        for (int i=0;i<n;i++){
            p[i] = Integer.parseInt(peoples[i]);
        }
        Arrays.sort(p);
        int i = 0, j = n-1;
        int count = n;
        while (i < j){
            if (p[i] + p[j] <= limit){
                count--;
                i++;j--;
            }
            else
                j--;
        }
        System.out.println(count);
    }
}

发表于 2019-08-06 15:33:29 回复(0)