`
thrillerzw
  • 浏览: 138106 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

算法n个数按顺序分成m组,每组和尽量相近

阅读更多
package algorithm;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeMap;

/**
 * 
 * @Description: n个数按顺序分成m组,每组和尽量相近 
 * 思路:先递归求出所有切分点的组合方式,然后分别计算每组中的和,对每组和两两差值的绝对值累加,最小的为最优切分点。
 * 如:{1,2,3,4}分2组 可以{1}和{2,3,4} {1,2}和{3,4} {1,2,3}和{4}   不能为{1,3}{2,4} 
 * 缺点:当list很大,分的组很多的时候,效率很低,几十分钟才能算出来。
 * @author thrillerzw
 * @version 1.0
 * @create time 2014-4-28 下午6:47:19
 */
public class TestCombination {
	public static void main(String[] args) {
		List<Integer> lengthList = new ArrayList<Integer>();
		for(int i=0;i<6;i++){
			lengthList.add(new Random().nextInt(100));
		}
		long startTime=System.currentTimeMillis();
		int m = 3;
		List<List<Integer>> resultList = new ArrayList<List<Integer>>();
		if (lengthList.size() < m) {
			buildResultList(resultList, lengthList);
		} else {
			int endIndex = lengthList.size() - (m - 2);
			int[] tempArr = new int[m - 1];
			List<int[]> combList = new ArrayList<int[]>();
			int num = -1;
			//所有切分点的组合存入combList
			Combine(lengthList, m - 1, tempArr, 0, 0, combList);
			int[] resultArr = null;
			for (int[] combArr : combList) {
				for (int i = 0; i < combArr.length; i++) {
					System.out.print(combArr[i] + " ");
				}
				System.out.println();
				int[] sumArr = getSum(combArr, lengthList);
				int diffSum = computeDifferent(sumArr);
				if (diffSum < num || num == -1) {
					num = diffSum;
					System.out.println("num=" + num);
					resultArr = combArr;
				}
			}
			if (resultArr != null) {
				for (int result : resultArr) {
					System.out.print(result + " ");
				}
			}

			buildResultList(resultList, lengthList, resultArr);
		}
		long endTime=System.currentTimeMillis();
		long useTime=endTime-startTime;
		System.out.print(lengthList.size()+"个数分为"+m+"组使用毫秒时间"+useTime+" resultList=" + resultList);
	}
    //如果分组数m大于等于集合的长度。
	static void buildResultList(List<List<Integer>> resultList,
			List<Integer> dataList) {
		for (int i = 0; i < dataList.size(); i++) {
			List<Integer> list = new ArrayList<Integer>();
			list.add(dataList.get(i));
			resultList.add(list);
		}
	}

	// 根据最优切分点构建结果集
	static void buildResultList(List<List<Integer>> resultList,
			List<Integer> dataList, int[] resultArr) {
		if (resultList == null || dataList == null || resultArr == null) {
			return;
		}
		int j = 0;
		int maxJ = 0;
		for (int i = 0; i <= resultArr.length; i++) {
			if (i == resultArr.length) {
				maxJ = dataList.size();
			} else {
				maxJ = resultArr[i];
			}
			List<Integer> list = new ArrayList<Integer>();
			for (; j < maxJ; j++) {
				list.add(dataList.get(j));
			}
			resultList.add(list);
		}
	}
    //每种组合不同段的和。比如0--2  2--5   5--list的结尾
	static int[] getSum(int[] combArr, List<Integer> dataList) {
		if (combArr == null || dataList == null) {
			return null;
		}
		int[] sumArr = new int[combArr.length + 1];
		int j = 0;
		int sum = 0;
		int maxJ = 0;
		for (int i = 0; i <= combArr.length; i++) {

			if (i == combArr.length) {
				maxJ = dataList.size();
			} else {
				maxJ = combArr[i];
			}
			for (; j < maxJ; j++) {
				sum += dataList.get(j);
			}
			sumArr[i] = sum;
			System.out.println("sum=" + sum);
			sum = 0;
		}
		return sumArr;
	}

	// 数组中值两两比较,差的绝对值的和累加
	static int computeDifferent(int[] sumArr) {
		int diffSum = 0;
		for (int i = 0; i < sumArr.length; i++) {
			for (int j = i + 1; j < sumArr.length; j++) {
				diffSum += Math.abs(sumArr[i] - sumArr[j]);
			}
		}
		System.out.println("diffSum=" + diffSum);
		return diffSum;
	}

	// 所有切分点组合
	private static void Combine(List<Integer> lengthList, int num,
			int[] tempArr, int tempArrIndex, int low, List<int[]> combList) {
		if (lengthList == null || lengthList.size() < num) {
			return;
		}
		if (num == 0) {
			if (tempArr[tempArr.length - 1] != lengthList.size()) {
				combList.add(tempArr);
			}
		} else {
			for (int i = low; i < lengthList.size(); i++) {
				tempArr[tempArrIndex] = i + 1;
				Combine(lengthList, num - 1, tempArr, ++tempArrIndex, i + 1,
						combList);
				int[] newTempArr = new int[tempArr.length];
				System.arraycopy(tempArr, 0, newTempArr, 0, tempArr.length - 1);
				tempArr = newTempArr;
				tempArrIndex--;
			}
		}
	}

}

 

2、

package algorithm;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @Description: 按顺序累加,与平均值相差最小的分为一组。
 * 优点:解决数据、分组大时候,穷举所有组合效率低的问题。适合数据比较均匀的时候。
 * 缺点:大数集中分布到一头等特殊情况分组不好。
 * @author thrillerzw
 * @version 1.0
 * @create time 2014-4-30 上午9:52:16
 */
public class TestAverage {
	public static void main(String[] args) {
		List<Integer> lengthList = new ArrayList<Integer>();
		lengthList.add(1);
		lengthList.add(2);
		lengthList.add(8);
		lengthList.add(6);
		lengthList.add(4);
		lengthList.add(10);
	
		int m = 3;
		List<List<Integer>> resultList = new ArrayList<List<Integer>>();
		if (lengthList.size() < m) {
			buildResultList(resultList, lengthList);
		} else {
			int[] pointArr = findSplitPoint(lengthList, m);
			buildResultList(resultList, lengthList, pointArr);
		}
		System.out.print("resultList=" + resultList);
	}

	private static int[] findSplitPoint(List<Integer> lengthList, int m) {
		int totalNum = 0;
		for (int i = 0; i < lengthList.size(); i++) {
			totalNum += lengthList.get(i);
		}
		//平均值
		double average = (double) totalNum / (double) m;
		System.out.println("average=" + average);
		int groupNum = 0;
		int[] pointArr = new int[m - 1];
		int pointArrIndex = 0;
		double minDiffSum = -1;
		int i = 0;
		for (; i < lengthList.size(); i++) {
			int num = lengthList.get(i);
			//按顺序累加
			groupNum += num;
			double curDiffSum = Math.abs(groupNum - average);

			int surplusGroupNum = m - 1 - pointArrIndex;
			int surplusDataNum = lengthList.size() - i;
			int differNum = surplusDataNum - surplusGroupNum;
            
			if (differNum > 0) {
				//当前累加 与平均值的距离 < 上次累加与平均值的距离  
				if (curDiffSum < minDiffSum || minDiffSum == -1) {
					minDiffSum = curDiffSum;
				} else {
					//保存切分点
					pointArr[pointArrIndex] = i;
					if (pointArrIndex == m - 2) {
						break;
					}
					pointArrIndex++;
					groupNum = num;
					minDiffSum = Math.abs(num - average);
				}
			} else {
				//简单解决大数分布到头尾,不够分组的情况。把末尾的每个值单独分为一组。
				pointArr[pointArrIndex++] = i;
				int point = i + 1;
				for (int j = 0; j < surplusGroupNum - 1; j++) {
					pointArr[pointArrIndex++] = point++;
				}
				break;
			}

		}
		return pointArr;
	}

	static void buildResultList(List<List<Integer>> resultList, List<Integer> dataList) {
		for (int i = 0; i < dataList.size(); i++) {
			List<Integer> list = new ArrayList<Integer>();
			list.add(dataList.get(i));
			resultList.add(list);
		}
	}

	static void buildResultList(List<List<Integer>> resultList, List<Integer> dataList, int[] resultArr) {
		if (resultList == null || dataList == null || resultArr == null) {
			return;
		}
		int j = 0;
		int maxJ = 0;
		for (int i = 0; i <= resultArr.length; i++) {
			if (i == resultArr.length) {
				maxJ = dataList.size();
			} else {
				maxJ = resultArr[i];
			}
			List<Integer> list = new ArrayList<Integer>();
			for (; j < maxJ; j++) {
				list.add(dataList.get(j));
			}
			resultList.add(list);
		}
	}

}

 

0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics