說明
假設有個集合擁有m個元素,任意的從集合中取出n個元素,則這n個元素所形成的可能子集有那些?
解法
假設有5個元素的集點,取出3個元素的可能子集如下:
{1 2 3}、{1 2 4 }、{1 2 5}、{1 3 4}、{1 3 5}、{1 4 5}、{2 3 4}、{2 3 5}、{2 4 5}、{3 4 5}
這些子集已經使用字典順序排列,如此才可以觀察出一些規則:
- 如果最右一個元素小於m,則如同碼錶一樣的不斷加1
- 如果右邊一位已至最大值,則加1的位置往左移
- 每次加1的位置往左移後,必須重新調整右邊的元素為遞減順序
所以關鍵點就在於哪一個位置必須進行加1的動作,到底是最右一個位置要加1?還是其它的位置?
在實際撰寫程式時,可以使用一個變數positon來記錄加1的位置,position的初值設定為n-1,因為我們要使用陣列,而最右邊的索引值為最大
的n-1,在position位置的值若小於m就不斷加1,如果大於m了,position就減1,也就是往左移一個位置;由於位置左移後,右邊的元素會
經過調整,所以我們必須檢查最右邊的元素是否小於m,如果是,則position調整回n-1,如果不是,則positon維持不變。
#include <stdio.h> #include <stdlib.h>
#define MAX 20
int main(void) { int m, n; printf("輸入集合個數 m:"); scanf("%d", &m); printf("輸入取出元素 n:"); scanf("%d", &n);
int set[MAX]; int i; for(i = 0; i < n; i++) set[i] = i + 1; // 顯示第一個集合 for(i = 0; i < n; i++) printf("%d ", set[i]); putchar('\n'); int position = n - 1; while(1) { if(set[n-1] == m) position--; else position = n - 1;
set[position]++;
// 調整右邊元素 int j; for(j = position + 1; j < n; j++) set[j] = set[j-1] + 1; for(j = 0; j < n; j++) printf("%d ", set[j]); putchar('\n');
if(set[0] >= m - n + 1) break; }
return 0; }
import java.util.*; public class NofM implements Iterable<int[]>, Iterator<int[]> { private int m; private int[] set; private boolean first = true; private int position; public NofM(int n, int m) { this.m = m; position = n - 1; set = new int[n]; for(int i = 0; i < n; i++) set[i] = i + 1; } public Iterator<int[]> iterator() { return this; } public boolean hasNext() { return set[0] < m - set.length + 1; } public int[] next() { if(first) { first = false; } else { if(set[set.length-1] == m) position--; else position = set.length - 1;
set[position]++;
// 調整右邊元素 for(int i = position + 1; i < set.length; i++) set[i] = set[i-1] + 1; } return set; } public void remove() { throw new RuntimeException("Unsupported Operation"); } public static void main(String[] args) { for(int[] set : new NofM(3, 5)) { for(int i = 0; i < set.length; i++) { System.out.print(set[i]); } System.out.println(); } } }
class NofM: def __init__(self, n, m): self.__m = m self.__first = True self.__position = n - 1 self.__set = [i + 1 for i in range(n)] def __iter__(self): return self def __next__(self): if self.__set[0] >= self.__m - len(self.__set) + 1: raise StopIteration if self.__first: self.__first = False else: if self.__set[len(self.__set) - 1] == self.__m: self.__position -= 1 else: self.__position = len(self.__set) - 1 self.__set[self.__position] += 1 for i in range(self.__position + 1, len(self.__set)): self.__set[i] = self.__set[i - 1] + 1 return self.__set for set in NofM(3, 5): for i in range(len(set)): print(set[i], end="") print()
class NofM(n: Int, val m: Int) extends Iterator[Array[Int]] { private var position = n - 1 private var first = true private val set = (for(i <- 0 until n) yield i + 1).toArray def hasNext() = { set(0) < m - set.length + 1 } def next() = { if(first) { first = false } else { position = if(set(set.length - 1) == m) position - 1 else set.length - 1 set(position) = set(position) + 1 for(i <- position + 1 until set.length) { set(i) = set(i - 1) + 1 } } set } }
for(set <- new NofM(3, 5)) { set.foreach(print) println() }
class NofM def initialize(n, m) @m = m @first = true @position = n - 1 @set = (1..n).to_a end def each while @set[0] < @m - @set.length + 1 if @first @first = false else if @set[@set.length - 1] == @m @position -= 1 else @position = @set.length - 1 end @set[@position] += 1 (@position + 1).upto(@set.length - 1) { |i| @set[i] = @set[i - 1] + 1 } end yield(@set) end end end
NofM.new(3, 5).each { |set| set.each { |ele| print ele } puts }
|