Хорошо, вот простая эмуляция процесса, который вы описали. Но я использую двоичные числа для представления набора, это облегчает манипуляции. Например, число 19 - это 10011 в двоичной форме: это означает, что студенты 0, 3 и 4 выбраны (в этих позициях 1).
Сначала маленький помощник.
// return all subsets of 'set', having size 'subsetSize'
Set<Integer> allSubsets(int set, int subsetSize) {
Set<Integer> result = new HashSet<Integer>();
if (subsetSize == 0) {
result.add(0);
return result;
}
if (set == 0) {
return result;
}
// check if 1st element is present
if (set % 2 == 1) {
// use 1st element, one less element to collect
for (Integer i : allSubsets(set / 2, subsetSize - 1)) {
result.add(i * 2 + 1);
}
}
// not use 1st element
for (Integer i : allSubsets(set / 2, subsetSize)) {
result.add(i * 2);
}
return result;
}
И основная программа. Предложения приветствуются.
int N = 5;
int M = 3;
int Z = 2;
List<Integer> result = new ArrayList<Integer>();
// get all groups of M elements from 'wholeSet'
int wholeSet = (1 << N) - 1;
for (int s : allSubsets(wholeSet, M)) {
// Check all subsets of 'Z' elements from set 's'
boolean valid = true;
for (int t : allSubsets(s, Z)) {
// check if this Z-element subset already was used
for (int past : result) {
// check if 't' is subset of 'past' set
if ((past|t) == past) {
valid = false;
break;
}
}
if (!valid) {
break;
}
}
if (valid) {
// none of Z-element subsets of 's' were used before
result.add(s);
}
}
Но для больших вводов могут потребоваться улучшения (например, памятка ). Но сейчас, так как вы не говорите, какой вклад вы ожидаете, я предполагаю, что это достаточно хорошо.