輸入兩個整數n 和m,從數列1,2,3.......n 中隨意取幾個數, 使其和等於m ,要求將其中所有的可能組合列出來
阿新 • • 發佈:2019-02-18
中興面試題之一,難度係數中。
題目描述如下:輸入兩個整數n 和m,從數列1,2,3.......n 中隨意取幾個數,
使其和等於m ,要求將其中所有的可能組合列出來。
邏輯分析:
1、比起微軟,google,百度這些公司,中興的面試題還是略顯逗比的,並非是說難度上差異,而是中興的題目總是顯得不倫不類。本題其實就是考察數的組合,對於此類問題,通常手段都是遞迴,而我們的目標就在於找出遞迴式。
2、問題其實本質上就是0/1揹包問題,對於每一個n,我們採用貪婪策略,先考察是否取n,如果取n,那麼子問題就變成了find(n-1,m-n),而如果捨棄n,子問題則為find(n-1,m)。至此,我們利用DP思想找到了遞迴式(很多時候,所謂動態規劃,貪婪只是一念之差)。
3、那麼,如何制定解的判定策略?我們知道,遞迴需要邊界條件,而針對揹包問題,邊界條件只有兩種,如果n<1或者m<1,那麼便相當於“溢位”,無法combo出m,而另一種可能就是在剩餘的n個裡恰好滿足m==n,即此時 揹包剛好填充滿,輸出一組解單元。除此之外,再無其他。
C原始碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> int length; void findCombination(int n,int m,int *flag) { if(n < 1 || m < 1) return; if(n > m) n = m; if(n == m) { flag[n-1] = 1; for(int i=0;i<length;i++) { if(flag[i] == 1) printf("%d\t",i+1); } printf("\n"); flag[n-1] = 0; } flag[n-1] = 1; findCombination(n-1,m-n,flag); flag[n-1] = 0; findCombination(n-1,m,flag); } int main() { int n, m; scanf("%d%d",&n,&m); length = n; int *flag = (int*)malloc(sizeof(int)*length); findCombination(n,m,flag); free(flag); return 0; }
注:我們設定flag揹包,用來標註對應的n+1是否被選中,1表示被選中,0則表示未選中,每當滿足m==n時,則輸出一組解。程式容易產生邏輯bug的地方在於length的使用(讀者可以思考一下為何需要全域性變數length,而不是直接使用n來代替for迴圈)。