m選n組合的兩種演算法(C語言實現)
阿新 • • 發佈:2019-01-08
原問題:
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
1. 遞迴演算法
即首先選擇n,然後遞迴地從剩下的1...n-1選擇k-1個數,然後選擇n-1,然後遞迴地從剩下的1...n-2選擇k-1個數,直到選到k。
//d儲存選擇的數,NUM指示選擇多少個數,即初始k的大小 void Recursive_SelectK(int n,int k,int d[],const int NUM) { int i = n; if(k > n) return; while(i>=k) { d[NUM-k] = i; if(k>1) Recursive_SelectK(i-1,k-1,d,NUM); else { int j = 0; while(j<NUM) { printf("%d ",d[j]); j++; } printf("\n"); } i--; } }
2. 01轉換演算法
首先初始化一個n大小的陣列,0代表未選擇,1代表選擇,每次都有k個1,n-k個0,當把所有的01組合列出,即是n選k的所有組合。得到所有01組合的演算法描述如下:
- 首先初始化,將陣列前k個元素置1,表示第一個組合為前k個數。
- 然後從左到右掃描陣列元素值的“10”組合,找到第一個“10”組合後將其變為“01”組合;
- 同時將其左邊的所有“1”全部移動到陣列的最左端。
- 當第一個“1”移動到陣列的n-k的位置,即n個“1”全部移動到最右端時,就得到了最後一個組合。
void SelectK_01(int n,int k) { //true is selected bool *nselect = (bool *)malloc(n*sizeof(bool)); int i = 0; //初始化第一個組合,即選擇前k個數 while(i<n) { if(i<k) nselect[i] = true; else nselect[i] = false; i++; } i = 0; while(i<n){ if(nselect[i]) printf(" %d ",i+1); i++; } printf("\n"); i=0; while(i<n-1) { //找到第一個10組合,並交換10的位置 if(nselect[i] && !nselect[i+1]) { int temp = nselect[i]; int x=0,y=0; nselect[i] = nselect[i+1]; nselect[i+1] = temp; //將該組合左邊所有的1移至陣列最左邊 while(y<i) { if(nselect[y]) { temp = nselect[y]; nselect[y] = nselect[x]; nselect[x] = temp; x++; } y++; } i = 0; while(i<n){ if(nselect[i]) printf(" %d ",i+1); i++; } printf("\n"); i = (x==0?0:x-1); } else i++; } free(nselect); }