1. 程式人生 > >java實戰演算法根據個數百分比,排序金額分配案件金額也趨近百分比

java實戰演算法根據個數百分比,排序金額分配案件金額也趨近百分比

使用場景:

給n個員工分配n個案子。條件是按個數比例分配。分配後的案件金額也趨近於個數的比例,並且趨近公平分配。

設計思路

這裡比較複雜的地方就是怎麼按個數佔比分配,案件金額總數也趨近個數佔比。並且趨近公平

例如10個按鍵,案件金額為1,2,3,4,5,6,7,8,9,10

第一種情況偶數分配:

給兩個人分案件,一個分配40%一個分配60%,案件個數就是4:6  = 2:3  怎麼讓金額也趨近2:3 

設計思路是先將案件按金額大小排序從頭尾獲取,第一個人獲取四個案件,這四個案件分別從頭尾獲取,例如當A先獲取四個案件是,A拿到的案件分別是1,10,2,9。B獲取到的就是3,8,4,7,5,6,金額的比例是 22:33 趨近 2:3的案件佔比。

第二種情況奇數數分配:

給兩個人分案件,一個分配30%一個分配70%,案件個數就是3:7怎麼讓金額也趨近3:7=0.42設計思路是還是先將案件按金額大小排序從頭尾獲取,第一個人獲取四個案件,這四個案件分別從頭尾獲取,例如當                                                                A先獲取一箇中間的案件然後剩下的按偶數的從頭尾取案件,同理第二個人也一樣A拿到的案件分別是5,1,10  B獲取到的就是6,2,9,3,8,4,7 金額的比例是 16:39=0.41趨近於0.42的案件佔比。

當總件數跟百分比的乘機為有小數點的時候,向下取整,比如1.4  取 1。最後一個人直接取剩下所有。

偶數分配圖示

奇數分配圖示


Java程式碼:

//*********************************************催收公司分案相關**************************//
	@Override
	public List<User> updateAutoCaseSplit(CaseHead head,CaseParamsExtend exParams,List<User> users,String tableName) {
		if (head == null){
			return users;
		}
		if (users == null || users.size() == 0){
			return users;
		}
		//獲取案件
        List<CaseHead> heads=caseHeadMapper.getCaseHeadAll(head,exParams,tableName);
		if (heads == null || heads.size() == 0){
			return users;
		}
		// 進行分案處理 1.案件金額排序
		sortCases(heads);
		Integer casecount=heads.size();//案件個數
		//將使用者排序打亂
		Collections.shuffle(users);

		List<CaseHead> caselist=new ArrayList<CaseHead>();//剩餘案件
		caselist=heads;
		//迴圈遍歷員工
		for (int i = 0; i <users.size() ; i++) {

			//計算使用者分得幾個案子  案件數*百分比
			if (i != users.size()-1){
				double userCaseCount=casecount*users.get(i).getSplitRate()/100;
				Integer count=(int)Math.floor(userCaseCount);
				//根據分的案件個數從頭尾取值 如果有奇數就奇數在中間取一個變為偶數在頭尾取值
				if (count%2==0){//偶數
					Integer total=count/2; //頭尾各取total個
					for (int j = 0; j < total; j++) {
						int end=caselist.size()-1;
						users.get(i).addCaseHead(caselist.get(0));//頭
						users.get(i).addCaseHead(caselist.get(end));//尾
						caselist.remove(end);
						caselist.remove(0);

					}
				}else{//奇數
					if (count == 1){//如果只有一個案子那麼在中間取一個就退出
						int middle=(int)Math.floor(caselist.size()/2);
						users.get(i).addCaseHead(caselist.get(middle));//中
						caselist.remove(middle);
					}else{
						//第一個取中間
						int middle=(int)Math.floor(caselist.size()/2);
						users.get(i).addCaseHead(caselist.get(middle));//中
						caselist.remove(middle);
						//剩下的跟偶數一致
						int total=(count-1)/2;
						for (int a = 0; a < total; a++) {
							int end=caselist.size()-1;
							users.get(i).addCaseHead(caselist.get(0));//頭
							users.get(i).addCaseHead(caselist.get(end));//尾
							caselist.remove(end);
							caselist.remove(0);

						}
					}
				}

			}else{//最後一個不用計算案件數。剩餘案件全是最後一個的這是為了以上幾個計算有小數點取整誤差
				for (CaseHead caseHead : caselist) {
					users.get(i).addCaseHead(caseHead);
				}
			}
		}

		return  users;
	}

	/**
	 * 執行分案
	 * */
	@Override
	public List<User> updateCaseSplit(List<User> users, String tableName) throws Exception {

		for (int i = 0; i <users.size() ; i++) {

		}
		return null;
	}

	//案件按照金額排序
	private void sortCases(List<CaseHead> caseHeads) {
		Collections.sort(caseHeads, new Comparator<CaseHead>() {
			@Override
			public int compare(CaseHead o1, CaseHead o2) {
				return (int) (o2.getMoney() - o1.getMoney()) * 1000;
			}
		});
	}


	//*********************************************催收公司分案相關結束************************//


	//==================分案相關操作
	@Transient
	private double splitRate;//分案佔比;
	@Transient
	private double splitTotal;//分案總金額
	@Transient
	private int splitCount;//分案總件數
	@Transient
	private List<User> userList;//分案引數
	@Transient
	private List<CaseHead> caseList;//案件list


	public List<CaseHead> getCaseList() {
		return caseList;
	}

	public void setCaseList(List<CaseHead> caseList) {
		this.caseList = caseList;
	}

	public List<User> getUserList() {
		return userList;
	}

	public void setUserList(List<User> userList) {
		this.userList = userList;
	}

	public void addCaseHead(CaseHead caseHead){
		if(caseList==null)
			caseList=new ArrayList<>();
		caseList.add(caseHead);
		//總額 件數
		splitCount++;
		splitTotal+=caseHead.getMoney();
	}


將分完的結果通過物件返回給前臺頁面