问题:对于N个数字,输出所有分M组,组间和组内的顺序无关的序列。
解析:排列组合问题的平均分组问题。网上没有找到现成的,就写了一个。 Java 编程,调试通过
设G(N,M) 为分组函数,程序的思想是
- M组内每组最小值按组间从小到大输出
- 对于第一组,1肯定是第一个元素,没有其他情况,则其他第一组内其他元素C(N-1,N/M-1),C为组合数,也就是从N-1中选N/M-1个元素填到第一组,对于其每种情况,第二组同样处理,这样,推导到出G(N,M)=C(N-1,N/M-1) * G(N-N/M,M-1)。
- 算出多少中情况不难,难在输出这些序列。
缘起:女儿小学一年级的思维训练题
题目可以简化为 1选7,然后,6分3组
G(6,3) = C(5,1)*G(4,2) = C(5,1)*C(3,1) = 15种
这里的代码输出了15种情况,为
[1]1 2 | 3 4 | 5 6 |
[2]1 2 | 3 5 | 4 6 |
[3]1 2 | 3 6 | 4 5 |
[4]1 3 | 2 4 | 5 6 |
[5]1 3 | 2 5 | 4 6 |
[6]1 3 | 2 6 | 4 5 |
[7]1 4 | 2 3 | 5 6 |
[8]1 4 | 2 5 | 3 6 |
[9]1 4 | 2 6 | 3 5 |
[10]1 5 | 2 3 | 4 6 |
[11]1 5 | 2 4 | 3 6 |
[12]1 5 | 2 6 | 3 4 |
[13]1 6 | 2 3 | 4 5 |
[14]1 6 | 2 4 | 3 5 |
[15]1 6 | 2 5 | 3 4 |
代码
其主要函数 SplitGroup2::next_sg()用来输出下一组组合。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SplitGroup2 {
private List<Integer> D = new ArrayList<Integer>();
private int N = 0;
private int M = 0;
private int id = 0;
public List<Integer> next_sg() {
boolean isfound = false;
if (D.size() == 0) {
for (int i = 1; i <= N; i++)
D.add(i);
isfound = true;
} else {
int r = M - 2;
int rsize = N / M;
while (isfound == false) {
int c0 = r * rsize;
int cX = c0 + rsize - 1;
if ((r < 0) || (c0 == cX) || cX < 1) // one element one group
{
break;
}
while ((cX != c0) && (isfound == false))
{
List<Integer> s1 = D.subList((r+1)*rsize, D.size());
Collections.sort(s1);
int cc = cX;
int val = D.get(cc);
for (int i = 0; i < s1.size(); i++) {
if (s1.get(i) > val) {
isfound = true;
int tmp = D.set(cc, s1.get(i));
D.set(i+(r+1)*rsize, tmp);
cc++;
if(cc > c0 + rsize -1)
break;
}
}
if(isfound)
{
List<Integer> slast = D.subList((r+1)*rsize, D.size());
Collections.sort(slast);
}
if (isfound == false) {
cX = cX - 1;
if (cX == c0) {
r--;
if (r < 0)
break;
}
}
}
}
}
id = (isfound)?id+1:0;
if(isfound == false)
{
D.clear();
}
return D;
}
public SplitGroup2(int n, int m) {
N = n;
M = m;
if (N < M)
throw new IllegalArgumentException("N < M !!");
if (N % m != 0)
throw new IllegalArgumentException("N mod m <> 0");
D.clear();
}
public void PrintD() {
if (D.size() > 0) {
System.out.printf("[%d]\t",id);
for (int i = 0; i < D.size(); i++)
{
System.out.printf("%d ", D.get(i));
if((i+1) % (N/M) == 0)
System.out.print("| ");
}
System.out.printf("\n");
} else
System.out.printf("N/A\n");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SplitGroup2 sg = new SplitGroup2(6, 3);
List<Integer> retD;
do {
//for (int i = 0; i < 30; i++)
retD = sg.next_sg();
if(retD.size() > 0)
sg.PrintD();
} while (retD.size() > 0);
}
}