一、题目
1.原题
部门在进行需求开发时需要进行人力安排。
当前部门需要完成N个需求,
需求用requirements[]表示,
requirements[i]表示第i个需求的工作量大小,单位:人月。
这部分需求需要在M个月内完成开发,
进行人力安排后每个月的人力是固定的。
目前要求每个月最多有2个需求开发,
并且每个月需要完成的需求不能超过部门人力。
请帮部门评估在满足需求开发进度的情况下,
每个月需要的最小人力是多少?
2.题目理解
已知:
①当前部门要在M个月完成N个需求(requirements);
②每个需求(requirements[i]=x:该需求工作量为x人月,eg:某需求需要3个人做3个月,工作量就是3×3=9人月);
约束:
③每个月最多有两个需求开发(0≤N/M≤2)=>N≤2M;
④未知量:当前部门人力;
⑤每个月需要完成的需求不能超过部门人力:;
(以上两条可以忽略,因为已知条件才与每月所需最小人力相关,④和⑤只是为了补全现实考虑;当然为了更完善也可以设置部门人力,判断是否可以接这个阶段项目。)
求解:
⑥满足需求开发进度的情况下,每个月需要的最小人力。
每个月所需的最小人力是指,为了在给定的月份内完成所有需求,每个月分配的工作量的最小上限。如果每个月的人力小于这个最小值,那么就无法在规定的月份内完成所有需求。
二、思路与代码过程
1.思路
2.代码过程
①main函数
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入当前项目所需月数:");
int M = sc.nextInt();
System.out.println("请输入当前部门在M个月需要完成的需求数:");
int N = sc.nextInt();
if (N>2*M){
System.out.println("当前需求和时间安排不合理");
return;
}
System.out.println("请输入每个需求的工作量大小:");
int[] requirements = new int[N];
for (int i = 0; i < N; i++) {
requirements[i] = sc.nextInt();
}
System.out.println(Arrays.toString(requirements));
int[] sortedRequirements = Arrays.stream(requirements)
.sorted()
.toArray();
System.out.println(Arrays.toString(sortedRequirements));
//最小值是一个月做一个需求,人数刚好能满足最低需求
int minRequirement = Arrays.stream(requirements).max().orElseThrow();
//最大值是一个月做完所有需求,人力需要满足工作量之和
int maxRequirement = Arrays.stream(requirements).sum();
System.out.println("下限:"+minRequirement);
System.out.println("上限:"+maxRequirement);
//二分法
int midRequirement = (maxRequirement+minRequirement)/2;
System.out.println("中间值:"+midRequirement);
ArrayList<Integer> list = Arrays.stream(sortedRequirements) // 创建一个 IntStream
.boxed() // 将 IntStream 转换为 Stream<Integer>
.collect(Collectors.toCollection(ArrayList::new));
System.out.println(list);//
int lowestHuman = CountHum(M,list,minRequirement,midRequirement,maxRequirement);
System.out.println("在满足需求开发进度的情况下,每个月需要的最小人力是:"+lowestHuman);
System.out.println("请输入当前部门人力数量:");
int P = sc.nextInt();
if (P>=lowestHuman){
System.out.println("当前项目部门可以承接。");
}else {
System.out.println("当前项目部门不可以承接。");
}
}
②全局变量
static int comWorkmax =Integer.MAX_VALUE;
③CountHum函数
/*
工作量(人月)=所需人数*所需月数
总工作量=sum(requirements)=requirements[0]+..+requirements[n-1]
在组合的工作量小于等于当前mid的值的前提下,对需求进行组合
组合(最多含有2个需求):re[x]+re[y]
总工作量=组合1+组合2+..
将当前需求列表按照小于当前mid的要求组合完之后,输出组合数目,即所需月数month
若month小于等于需要完成任务的月份,则继续缩小mid
在mid的前提下继续组合,直到找到最小的
*/
private static int CountHum(int m,ArrayList<Integer> Requirements,int minRequirement,int midRequirement,int maxRequirement) {
int month = Integer.MAX_VALUE;
ArrayList<Integer> requirements = new ArrayList<>(Requirements);
//贪心算法:找到组合起来最接近mid的组合
//eg:mid=29,找两个组合起来的值,或一个比他小而且接近它的排序
//先比大小mid是否大于最大值,是的话采用两个数的组合,且组合值不大于29
//若等于最大值,则组合1:最大值,组合二继续寻找
//因为边界设定不可能小于最大值!!!
//eg:组合1:9+12=21,移除这两个需求,
// 找组合2:继续找两个合起来小于29且当前最大的
//组合3重复以上,直到需求被全部安排好
//输出此时的组合数量
//若满足小于等于M,则继续调小
ArrayList<int[]> combinations= new ArrayList<>();
ArrayList<int[]> Combination = findCombine(midRequirement,requirements,combinations);
month = Combination.size();
comWorkmax = Combination.get(0)[0]+Combination.get(0)[1];
//组合完成后,看花费月数,若月数满足则继续分割
if(month<m) {//每个月分太多了,完成太快
midRequirement = (minRequirement + midRequirement) / 2;
maxRequirement = (minRequirement + maxRequirement) / 2;
//min不改变
CountHum(m,requirements,minRequirement,midRequirement,maxRequirement);
}
else if (month>m) {//每个月分太少了,完成太慢
midRequirement = (midRequirement+ maxRequirement)/2;
minRequirement = (minRequirement+maxRequirement)/2;
//max不改变
CountHum(m,requirements,minRequirement,midRequirement,maxRequirement);
} else if (month==m) {
midRequirement = (midRequirement+ minRequirement)/2;
maxRequirement = (minRequirement + maxRequirement) / 2;
ArrayList<Integer> requirements1 = new ArrayList<>(Requirements);
ArrayList<int[]> combinations1= new ArrayList<>();
ArrayList<int[]> Combination1 = findCombine(midRequirement,requirements1,combinations1);
int month1 = Combination1.size();
if(month1==m){
int comWorkmax1 = Combination1.get(0)[0]+Combination1.get(0)[1];
if(comWorkmax1<comWorkmax){
CountHum(m,requirements,minRequirement,midRequirement,maxRequirement);
}else if(comWorkmax1==comWorkmax){
return comWorkmax;
}
}else{
return comWorkmax;
}
}
int minComWorkmax = Integer.MAX_VALUE;
minComWorkmax = Math.min(minComWorkmax,comWorkmax);
return minComWorkmax;
}
④findCombine函数
//贪心算法:找到组合起来最接近mid的组合
//eg:mid=29,找两个组合起来的值,或一个比他小而且接近它的排序
//因为边界设定不可能小于最大值!!!
//先看是否有两个数组合小于等于mid,是的话采用两个数的组合,并移除
//若当前列表,没有两个数组合小于等于mid,就按差值最小依次加入
//eg:组合1:9+12=21,移除这两个需求,
// 找组合2:继续找两个合起来小于29且当前最大的
//组合3重复以上,直到需求被全部安排好
//输出此时的组合数量
//若满足小于等于M,则继续调小
private static ArrayList<int[]> findCombine(int midRequirement, ArrayList<Integer> List,ArrayList<int[]> combination) {
ArrayList<Integer> list = new ArrayList<>(List);
int smallestDifference = Integer.MAX_VALUE;
//空了就返回
if (!list.isEmpty()){
//若仍有元素
if (list.size() >= 1) {
//剩下一个直接加入
if (list.size() == 1) {
combination.add(new int[]{0,list.get(0)});
list.remove(0);
findCombine(midRequirement, list,combination);
} else if(list.size() >= 2) {
//list有起码两个元素,寻找组合可能
int[] combine1 = new int[2];
int currentListSize = list.size();
boolean noCombination = true;
ArrayList<Integer> NoCombination = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {//避免自身重复
int combines = list.get(i) + list.get(j);
int difference = midRequirement - combines;
if (difference >= 0) {
noCombination = false;
int currentDifference = smallestDifference;
smallestDifference = Math.min(smallestDifference, difference);
if (smallestDifference!=currentDifference) {
combine1[0] = list.get(i);
combine1[1] = list.get(j);
}
}
}
//一轮组合后没有组合成功,说明当前数和任意一个数都无法组合,只能solo,加入不能组合表
if (noCombination){
NoCombination.add(list.get(i));
combination.add(new int[]{list.get(i),0});
}
}
}
if (combine1[1]!=0){//处理有组合的
combination.add(combine1);
list.remove(Integer.valueOf(combine1[0]));
list.remove(Integer.valueOf(combine1[1]));
findCombine(midRequirement, list,combination);
}
}
}
}
return combination;
}
三、运行结果
1.运行截图
2.带数据分析运行结果
请输入当前项目所需月数:
3
请输入当前部门在M个月需要完成的需求数:
4
请输入每个需求的工作量大小:
3 5 3 4
[3, 5, 3, 4]
[3, 3, 4, 5]
下限:5
上限:15
中间值:10
[3, 3, 4, 5]
**********************************CountNum start************************************************
countnum requirment:[3, 3, 4, 5]
--------------findCombine---------------------
当前mid为:10
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:3
当前组合值为:6,当前差值为:4
最小差值:4
循环内 当前最小差值组合:3,3
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:3
最小差值:3
循环内 当前最小差值组合:3,4
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:2
最小差值:2
循环内 当前最小差值组合:3,5
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:3
最小差值:2
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:2
最小差值:2
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:4,当前j为:5
当前组合值为:9,当前差值为:1
最小差值:1
循环内 当前最小差值组合:4,5
--------j循环结束·--------
--------------------i循环------------------------
--------j循环结束·--------
---------------i循环结束-------------------
[]
-------------循环外---------
当前最小差值组合:4,5
当前组合1:[4, 5]
当前list:[3, 3]
--------------findCombine---------------------
当前mid为:10
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:3
当前组合值为:6,当前差值为:4
最小差值:4
循环内 当前最小差值组合:3,3
--------j循环结束·--------
--------------------i循环------------------------
--------j循环结束·--------
---------------i循环结束-------------------
[]
-------------循环外---------
当前最小差值组合:3,3
当前组合1:[3, 3]
当前list:[]
--------------findCombine---------------------
当前mid为:10
*****************CountNum中的findcombine之后**********************
CountNum中的组合:
[4, 5]
[3, 3]
组合中一个月最大工作量为comWorkmax:9
2
===============[3, 3, 4, 5]
当前mid为:10,只需要2个月,小于3个月,每个月分太多了,完成太快。
要求月数:3,下限:5,中间值:7,上限:10
**********************************CountNum start************************************************
countnum requirment:[3, 3, 4, 5]
--------------findCombine---------------------
当前mid为:7
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:3
当前组合值为:6,当前差值为:1
最小差值:1
循环内 当前最小差值组合:3,3
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:0
最小差值:0
循环内 当前最小差值组合:3,4
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-1
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:0
最小差值:0
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-1
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:4,当前j为:5
当前组合值为:9,当前差值为:-2
--------j循环结束·--------
--------------------i循环------------------------
--------j循环结束·--------
---------------i循环结束-------------------
[]
-------------循环外---------
当前最小差值组合:3,4
当前组合1:[3, 4]
当前list:[3, 5]
--------------findCombine---------------------
当前mid为:7
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-1
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:3,需要单走。
组合不成功后的com[3, 4]
组合不成功后的com[3, 0]
[3]
--------------------i循环------------------------
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:5,需要单走。
组合不成功后的com[3, 4]
组合不成功后的com[3, 0]
组合不成功后的com[5, 0]
[3, 5]
---------------i循环结束-------------------
[3, 5]
*****************CountNum中的findcombine之后**********************
CountNum中的组合:
[3, 4]
[3, 0]
[5, 0]
组合中一个月最大工作量为comWorkmax:7
3
===============[3, 3, 4, 5]
当前mid为:7需要3个月,等于3个月,进度刚刚好,可以继续缩小寻找
要求月数:3,下限:5,中间值:6,上限:7
--------------findCombine---------------------
当前mid为:6
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:3
当前组合值为:6,当前差值为:0
最小差值:0
循环内 当前最小差值组合:3,3
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:-1
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-2
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:-1
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-2
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:4,当前j为:5
当前组合值为:9,当前差值为:-3
--------j循环结束·--------
--------------------i循环------------------------
--------j循环结束·--------
---------------i循环结束-------------------
[]
-------------循环外---------
当前最小差值组合:3,3
当前组合1:[3, 3]
当前list:[4, 5]
--------------findCombine---------------------
当前mid为:6
--------------------i循环------------------------
--------j循环--------
当前i为:4,当前j为:5
当前组合值为:9,当前差值为:-3
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:4,需要单走。
组合不成功后的com[3, 3]
组合不成功后的com[4, 0]
[4]
--------------------i循环------------------------
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:5,需要单走。
组合不成功后的com[3, 3]
组合不成功后的com[4, 0]
组合不成功后的com[5, 0]
[4, 5]
---------------i循环结束-------------------
[4, 5]
*****************month1==m且comwork1<comwork中的findcombine之后**********************
CountNum中的组合:
[3, 3]
[4, 0]
[5, 0]
month1:3,当前m为:3
当前comWorkmax1为:6,当前comWorkmax为;7
comWorkmax1<comWorkmax
**********************************CountNum start************************************************
countnum requirment:[3, 3, 4, 5]
--------------findCombine---------------------
当前mid为:6
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:3
当前组合值为:6,当前差值为:0
最小差值:0
循环内 当前最小差值组合:3,3
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:-1
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-2
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:-1
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-2
--------j循环结束·--------
--------------------i循环------------------------
--------j循环--------
当前i为:4,当前j为:5
当前组合值为:9,当前差值为:-3
--------j循环结束·--------
--------------------i循环------------------------
--------j循环结束·--------
---------------i循环结束-------------------
[]
-------------循环外---------
当前最小差值组合:3,3
当前组合1:[3, 3]
当前list:[4, 5]
--------------findCombine---------------------
当前mid为:6
--------------------i循环------------------------
--------j循环--------
当前i为:4,当前j为:5
当前组合值为:9,当前差值为:-3
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:4,需要单走。
组合不成功后的com[3, 3]
组合不成功后的com[4, 0]
[4]
--------------------i循环------------------------
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:5,需要单走。
组合不成功后的com[3, 3]
组合不成功后的com[4, 0]
组合不成功后的com[5, 0]
[4, 5]
---------------i循环结束-------------------
[4, 5]
*****************CountNum中的findcombine之后**********************
CountNum中的组合:
[3, 3]
[4, 0]
[5, 0]
组合中一个月最大工作量为comWorkmax:6
3
===============[3, 3, 4, 5]
当前mid为:6需要3个月,等于3个月,进度刚刚好,可以继续缩小寻找
要求月数:3,下限:5,中间值:5,上限:6
--------------findCombine---------------------
当前mid为:5
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:3
当前组合值为:6,当前差值为:-1
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:-2
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-3
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:3,需要单走。
组合不成功后的com[3, 0]
[3]
--------------------i循环------------------------
--------j循环--------
当前i为:3,当前j为:4
当前组合值为:7,当前差值为:-2
--------j循环--------
当前i为:3,当前j为:5
当前组合值为:8,当前差值为:-3
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:3,需要单走。
组合不成功后的com[3, 0]
组合不成功后的com[3, 0]
[3, 3]
--------------------i循环------------------------
--------j循环--------
当前i为:4,当前j为:5
当前组合值为:9,当前差值为:-4
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:4,需要单走。
组合不成功后的com[3, 0]
组合不成功后的com[3, 0]
组合不成功后的com[4, 0]
[3, 3, 4]
--------------------i循环------------------------
--------j循环结束·--------
-------------------没组合判断------------------------
组合不成功,当前值:5,需要单走。
组合不成功后的com[3, 0]
组合不成功后的com[3, 0]
组合不成功后的com[4, 0]
组合不成功后的com[5, 0]
[3, 3, 4, 5]
---------------i循环结束-------------------
[3, 3, 4, 5]
*****************month1==m且comwork1<comwork中的findcombine之后**********************
CountNum中的组合:
[3, 0]
[3, 0]
[4, 0]
[5, 0]
month1:4,当前m为:3
当前值不可以再缩小了!
最低每月人力需求为:comWorkmax:6,我返回啦
************************************end**********************************************
6
************************************end**********************************************
6
在满足需求开发进度的情况下,每个月需要的最小人力是:6
请输入当前部门人力数量:
8
当前项目部门可以承接。
3.带数据分析完整代码
import java.util.*;
import java.util.stream.Collectors;
public class test32 {
public static void main(String[] args) {
///*
Scanner sc = new Scanner(System.in);
System.out.println("请输入当前项目所需月数:");
int M = sc.nextInt();
System.out.println("请输入当前部门在M个月需要完成的需求数:");
int N = sc.nextInt();
if (N>2*M){
System.out.println("当前需求和时间安排不合理");
return;
}
System.out.println("请输入每个需求的工作量大小:");
int[] requirements = new int[N];
for (int i = 0; i < N; i++) {
requirements[i] = sc.nextInt();
}
System.out.println(Arrays.toString(requirements));
int[] sortedRequirements = Arrays.stream(requirements)
.sorted()
.toArray();
System.out.println(Arrays.toString(sortedRequirements));
//最小值是一个月做一个需求,人数刚好能满足最低需求
int minRequirement = Arrays.stream(requirements).max().orElseThrow();
//最大值是一个月做完所有需求,人力需要满足工作量之和
int maxRequirement = Arrays.stream(requirements).sum();
System.out.println("下限:"+minRequirement);
System.out.println("上限:"+maxRequirement);
//二分法
int midRequirement = (maxRequirement+minRequirement)/2;
System.out.println("中间值:"+midRequirement);
ArrayList<Integer> list = Arrays.stream(sortedRequirements) // 创建一个 IntStream
.boxed() // 将 IntStream 转换为 Stream<Integer>
.collect(Collectors.toCollection(ArrayList::new));
System.out.println(list);//
int lowestHuman = CountHum(M,list,minRequirement,midRequirement,maxRequirement);
System.out.println("在满足需求开发进度的情况下,每个月需要的最小人力是:"+lowestHuman);
System.out.println("请输入当前部门人力数量:");
int P = sc.nextInt();
if (P>=lowestHuman){
System.out.println("当前项目部门可以承接。");
}else {
System.out.println("当前项目部门不可以承接。");
}
//*/
/*复杂测试:
int M = 5;
int N = 7;
int[] requirements = {1 , 9 , 9 , 7 , 3 , 6 , 12};
//int[] requirements = {5, 2 , 3 ,4 , 5};
int[] sortedRequirements = Arrays.stream(requirements)
.sorted()
.toArray();
// */
/*简单测试:
int M = 3;
int N = 4;
int[] requirements = {3,5,3,4};
//int[] requirements = {5, 2 , 3 ,4 , 5};
int[] sortedRequirements = Arrays.stream(requirements)
.sorted()
.toArray();
*/
/*
System.out.println(Arrays.toString(requirements));
//最小值是一个月做一个需求,人数刚好能满足最低需求
int minRequirement = Arrays.stream(requirements).max().orElseThrow();
//最大值是一个月做完所有需求,人力需要满足工作量之和
int maxRequirement = Arrays.stream(requirements).sum();
System.out.println("下限:"+minRequirement);
System.out.println("上限:"+maxRequirement);
//二分法
int midRequirement = (maxRequirement+minRequirement)/2;
System.out.println("中间值:"+midRequirement);
ArrayList<Integer> list = Arrays.stream(sortedRequirements) // 创建一个 IntStream
.boxed() // 将 IntStream 转换为 Stream<Integer>
.collect(Collectors.toCollection(ArrayList::new));
System.out.println(list);//
int lowestHuman = CountHum(M,list,minRequirement,midRequirement,maxRequirement);
System.out.println("在满足需求开发进度的情况下,每个月需要的最小人力是:"+lowestHuman);
*/
}
/*
//工作量(人月)=所需人数*所需月数
//总工作量=sum(requirements)=requirements[0]+..+requirements[n-1]
//在组合的工作量小于等于当前mid的值的前提下,对需求进行组合
//组合(最多含有2个需求):re[x]+re[y]
// 总工作量=组合1+组合2+..
//将当前需求列表按照小于当前mid的要求组合完之后,输出组合数目,即所需月数month
//若month小于等于需要完成任务的月份,则继续缩小mid
//在mid的前提下继续组合,直到找到最小的
*/
//static int lowestHU = Integer.MAX_VALUE;
static int comWorkmax =Integer.MAX_VALUE;
private static int CountHum(int m,ArrayList<Integer> Requirements,int minRequirement,int midRequirement,int maxRequirement) {
System.out.println("**********************************CountNum start************************************************");
int month = Integer.MAX_VALUE;
ArrayList<Integer> requirements = new ArrayList<>(Requirements);
System.out.println("countnum requirment:"+requirements);//
//贪心算法:找到组合起来最接近mid的组合
//eg:mid=29,找两个组合起来的值,或一个比他小而且接近它的排序
//先比大小mid是否大于最大值,是的话采用两个数的组合,且组合值不大于29
//若等于最大值,则组合1:最大值,组合二继续寻找
//因为边界设定不可能小于最大值!!!
//eg:组合1:9+12=21,移除这两个需求,
// 找组合2:继续找两个合起来小于29且当前最大的
//组合3重复以上,直到需求被全部安排好
//输出此时的组合数量
//若满足小于等于M,则继续调小
ArrayList<int[]> combinations= new ArrayList<>();
ArrayList<int[]> Combination = findCombine(midRequirement,requirements,combinations);
System.out.println("*****************CountNum中的findcombine之后**********************");
System.out.println("\nCountNum中的组合:");
for (int[] combination : Combination) {
System.out.println(Arrays.toString(combination));
}
month = Combination.size();
comWorkmax = Combination.get(0)[0]+Combination.get(0)[1];
System.out.println("组合中一个月最大工作量为comWorkmax:"+comWorkmax);
System.out.println(month);
System.out.println("==============="+requirements);
//组合完成后,看花费月数,若月数满足则继续分割
if(month<m) {//每个月分太多了,完成太快
System.out.println("当前mid为:"+midRequirement+",只需要" + month + "个月,小于" + m + "个月,每个月分太多了,完成太快。");
midRequirement = (minRequirement + midRequirement) / 2;
maxRequirement = (minRequirement + maxRequirement) / 2;
//min不改变
System.out.println("要求月数:"+m+",下限:"+minRequirement+",中间值:"+midRequirement+",上限:"+maxRequirement);
CountHum(m,requirements,minRequirement,midRequirement,maxRequirement);
}
else if (month>m) {//每个月分太少了,完成太慢
System.out.println("当前mid为:"+midRequirement+"需要" + month + "个月,大于" + m + "个月,每个月分太少了,完成太慢。");
midRequirement = (midRequirement+ maxRequirement)/2;
minRequirement = (minRequirement+maxRequirement)/2;
//max不改变
System.out.println("要求月数:"+m+",下限:"+minRequirement+",中间值:"+midRequirement+",上限:"+maxRequirement);
CountHum(m,requirements,minRequirement,midRequirement,maxRequirement);
} else if (month==m) {
System.out.println("当前mid为:"+midRequirement+"需要" + month + "个月,等于" + m + "个月,进度刚刚好,可以继续缩小寻找");//
midRequirement = (midRequirement+ minRequirement)/2;
maxRequirement = (minRequirement + maxRequirement) / 2;
System.out.println("要求月数:"+m+",下限:"+minRequirement+",中间值:"+midRequirement+",上限:"+maxRequirement);
///*
ArrayList<Integer> requirements1 = new ArrayList<>(Requirements);
ArrayList<int[]> combinations1= new ArrayList<>();
ArrayList<int[]> Combination1 = findCombine(midRequirement,requirements1,combinations1);
System.out.println("*****************month1==m且comwork1<comwork中的findcombine之后**********************");
System.out.println("\nCountNum中的组合:");
for (int[] combination : Combination1) {
System.out.println(Arrays.toString(combination));
}
int month1 = Combination1.size();
System.out.println("month1:"+month1+",当前m为:"+m);
if(month1==m){
int comWorkmax1 = Combination1.get(0)[0]+Combination1.get(0)[1];
System.out.println("当前comWorkmax1为:"+comWorkmax1+",当前comWorkmax为;"+comWorkmax);
if(comWorkmax1<comWorkmax){
System.out.println("comWorkmax1<comWorkmax");
CountHum(m,requirements,minRequirement,midRequirement,maxRequirement);
}else if(comWorkmax1==comWorkmax){
System.out.println("当前值不可以再缩小了!");
System.out.println("最低每月人力需求为:comWorkmax:"+comWorkmax+",我返回啦");
return comWorkmax;
}
}else{
System.out.println("当前值不可以再缩小了!");
System.out.println("最低每月人力需求为:comWorkmax:"+comWorkmax+",我返回啦");
return comWorkmax;
}
//*/
}
System.out.println("************************************end**********************************************");
int minComWorkmax = Integer.MAX_VALUE;
minComWorkmax = Math.min(minComWorkmax,comWorkmax);
System.out.println(minComWorkmax);
return minComWorkmax;
}
//贪心算法:找到组合起来最接近mid的组合
//eg:mid=29,找两个组合起来的值,或一个比他小而且接近它的排序
//因为边界设定不可能小于最大值!!!
//先看是否有两个数组合小于等于mid,是的话采用两个数的组合,并移除
//若当前列表,没有两个数组合小于等于mid,就按差值最小依次加入
//eg:组合1:9+12=21,移除这两个需求,
// 找组合2:继续找两个合起来小于29且当前最大的
//组合3重复以上,直到需求被全部安排好
//输出此时的组合数量
//若满足小于等于M,则继续调小
private static ArrayList<int[]> findCombine(int midRequirement, ArrayList<Integer> List,ArrayList<int[]> combination) {
System.out.println("--------------findCombine---------------------");
System.out.println("当前mid为:"+midRequirement);
ArrayList<Integer> list = new ArrayList<>(List);
//System.out.println("findCom========list:"+list);
int smallestDifference = Integer.MAX_VALUE;
//空了就返回
if (!list.isEmpty()){
//若仍有元素
if (list.size() >= 1) {
//剩下一个直接加入
if (list.size() == 1) {
combination.add(new int[]{0,list.get(0)});
list.remove(0);
findCombine(midRequirement, list,combination);
} else if(list.size() >= 2) {
//list有起码两个元素,寻找组合可能
//System.out.println("findCom==222222======list:"+list);
int[] combine1 = new int[2];
int currentListSize = list.size();
boolean noCombination = true;
ArrayList<Integer> NoCombination = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
System.out.println("--------------------i循环------------------------");
for (int j = i + 1; j < list.size(); j++) {//避免自身重复
System.out.println("--------j循环--------");
System.out.println("当前i为:" + list.get(i) + ",当前j为:" + list.get(j));
int combines = list.get(i) + list.get(j);
int difference = midRequirement - combines;
System.out.println("当前组合值为:" + combines + ",当前差值为:" + difference);
if (difference >= 0) {
noCombination = false;
int currentDifference = smallestDifference;
smallestDifference = Math.min(smallestDifference, difference);
System.out.print("最小差值:" + smallestDifference);
System.out.println();
if (smallestDifference!=currentDifference) {
combine1[0] = list.get(i);
combine1[1] = list.get(j);
System.out.println("循环内 当前最小差值组合:"+combine1[0]+","+combine1[1]);
}
}
}
System.out.println("--------j循环结束·--------");
//System.out.println("Nom==?????????======Nom:"+NoCombination);
//一轮组合后没有组合成功,说明当前数和任意一个数都无法组合,只能solo,加入不能组合表
if (noCombination){
System.out.println("-------------------没组合判断------------------------");
// System.out.println("findCom==33333======list:"+list);
NoCombination.add(list.get(i));
System.out.println("\n组合不成功,当前值:"+list.get(i)+",需要单走。\n");
combination.add(new int[]{list.get(i),0});
for (int[] combination1 : combination) {
System.out.println("组合不成功后的com"+Arrays.toString(combination1));
}
System.out.println(NoCombination);
//只剩一个时,也要加入!!!
/*
if (list.size() == 1) {
NoCombination.add(list.get(0));
}
*/
//System.out.println("findCom==4444444======list:"+list);
//System.out.println("NoCom-----------------"+NoCombination);
}
}
System.out.println("---------------i循环结束-------------------");
System.out.println(NoCombination);
/*
if (!NoCombination.isEmpty()){
System.out.println("当前失败组合:"+NoCombination);
for (int i = 0; i < NoCombination.size(); i++){
System.out.println("\n组合不成功,当前值:"+NoCombination.get(i)+",需要单走。\n");
combination.add(new int[]{NoCombination.get(i), 0});
for (int[] combination1 : combination) {
System.out.println(Arrays.toString(combination1));
}
NoCombination.remove(NoCombination.get(i));
i--;
System.out.println("移除后的失败组合"+NoCombination);
}
for (int[] combination1 : combination) {
System.out.println("组合不成功后的com"+Arrays.toString(combination1));
}
System.out.println("组合不成功后的list"+list);
findCombine(midRequirement, list,combination);
}
*/
if (combine1[1]!=0){//处理有组合的
System.out.println("\n-------------循环外--------- \n" +
"当前最小差值组合:"+combine1[0]+","+combine1[1]);
System.out.println("当前组合1:"+Arrays.toString(combine1));
combination.add(combine1);
list.remove(Integer.valueOf(combine1[0]));
list.remove(Integer.valueOf(combine1[1]));
System.out.println("当前list:"+list);
findCombine(midRequirement, list,combination);
}
}
}
}
return combination;
}
}