华为4-22笔试——子序列最小和的最大值排列

一个序列 m个数,分成k个子序列,S[i]表示第i个子序列的和。要使S[i]的最小值尽可能大;S[i]的最小值相同时,按照S[0]最小、S[1]最小排列,输出第一个

样例1
输入:6 3
1 2 3 2 5 4
输出:1 2 3 / 2 5 / 4
样例2
输入:9 3
100 200 300 400 500 600 700 800 900
输出:100 200 300 400 500 / 600 700 / 800 900

解法1:暴力解法

import java.util.*;

public class Main {
    static PriorityQueue<String> queue;
    //储存最小和
    static int smin=0;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m = in.nextInt();
        int k = in.nextInt();
        int[] an = new int[m];
        for (int i = 0; i < m; i++) {
            an[i] = in.nextInt();
        }
        divideKInM(m,k,an);
        in.close();
    }

    private static void divideKInM(int m, int k, int[] an) {
        int[] s = new int[k];
        set = new HashSet<>();
        queue = new PriorityQueue<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                String[] o1s = o1.split("/");
                String[] o2s = o1.split("/");
                for (int i = 0; i < o1s.length; i++) {
                    int t = o1s[i].compareTo(o2s[i]);
                    if (t!=0) return t; 
                }
                return 0;
            }
        });
        dfs(an, 0,new StringBuilder(), k);
        System.out.println(queue.peek());
    }
    private static void dfs(int[] an, int ai, StringBuilder path, int k){
        if (ai==an.length){
            String pathS = path.toString();
            int thisSmin = minOfArray(pathS,k);
            if (thisSmin>smin){
                queue.clear();
                queue.add(pathS);
                smin = thisSmin;
            }else if (thisSmin == smin){
                queue.add(pathS);
            }
            return;
        }
        int sLen = path.length();
        dfs(an, ai+1,path.append(" "+an[ai]), k);
        //
        path.setLength(sLen);
        dfs(an, ai+1,path.append(" / "+an[ai]), k);

    }
    //求这种划分方法的子序列和最小值
    public static int minOfArray(String path,int k){
        String[] series = path.split("/");
        if (series.length!=k) return -1;
        int min = Integer.MAX_VALUE;
        for (String s:series ) {
            int temp = 0;
            String[] nums = s.split("\\s+");
            for (int i = 1; i < nums.length; i++) {
                try{
                    temp += Integer.parseInt(nums[i]);
                }catch (Exception e){

                }
            }
            min = Math.min(min,temp);
        }
        return min;
    }

}

解法2 数组和除以k得平均数,在子序列和到达平均数附近时,结合贪心 (暂时还没写)

解法3 最小m段和(动态规划) (暂时还没写)

最小m段和问题(动态规划)
最小m段和(JAVA版)

你可能感兴趣的:(题目,数据结构与算法)