第 21 題(數組)
2010 年中興面試題
編程求解:
輸入兩個整數 n 和 m,從數列 1,2,3.......n 中 隨意取幾個數,
使其和等於 m ,要求將其中所有的可能組合列出來.
我的思路:
從小到大 依次拼湊 后面選的數字 必須比前面大 保證不重復
如: n = 4 m = 8
1 2 3 4 超過8 去掉最后一個數 導數第二個數加一
1 2 4 小於8 最后一個數等於 4 去掉最后一個數 導數第二個數加一
1 3 4 符合 輸出 最后一個數等於 4 去掉最后一個數 導數第二個數加一
1 4 小於8 最后一個數等於 4 去掉最后一個數 導數第二個數加一
2 3 小於8
2 3 4 超過8 去掉最后一個數 導數第二個數加一
2 4 小於8 最后一個數等於 4 去掉最后一個數 導數第二個數加一
......
代碼:
/* 第 21 題(數組) 2010 年中興面試題 編程求解: 輸入兩個整數 n 和 m,從數列 1,2,3.......n 中 隨意取幾個數, 使其和等於 m ,要求將其中所有的可能組合列出來. start time = 15:55 end time = 17:03 */ #include <iostream> using namespace std; int FindCombine(int n, int m) { int method = 0; //一共有多少方法 if(m <= 0) { return 0; } else { int record[100]; //存儲組合當前的取值 for(int i = 0; i < 100; i++) { record[i] = i + 1; } int num = 0; //組合中數字的個數 int sum = 0; //組合中數字加起來的和 while(sum < m) { sum += record[num]; num++; if(sum == m) { method++; printf("組合%d:", method); for(int i = 0; i < num; i++) { printf("%d ", record[i]); } printf("\n"); if(num == 1) { return method; } } if((sum >= m) || (sum < m && record[num - 1] == n && num >= 2)) //如果大小超過m 或者 最后一個數字大小等於n 更新record { num--; sum -= record[num]; num--; sum -= record[num]; if(record[num] <= n) { record[num]++; for(int i = 1; i <= n - record[num]; i++) { record[i + num] = record[num] + i; } } } else if(sum < m && record[num - 1] == n && num == 1) { return method; } } } } int main() { int w = FindCombine(50, 100); return 0; }
慣例上網找別人的方法, 一看我就郁悶了, 居然可以用動態規划, 我的算法算是白學了, 到用的時候一點都想不起來。
http://blog.sina.com.cn/s/blog_7571423b01016707.html 里有個詳細的分析
http://www.cnblogs.com/freewater/archive/2012/07/16/2593218.html 里有非常精簡的代碼
vector<int> factors; void findFactor2(int sum,int n){ if(sum<0||n<0) return ; if(sum==0){ for(vector<int>::iterator iter=factors.begin();iter!=factors.end();++iter){ cout<<*iter<<' '; } cout<<endl; return; } factors.push_back(n);//典型的01背包問題 findFactor2(sum-n,n-1);//放n,n-1個數填滿sum-n factors.pop_back(); findFactor2(sum,n-1);//不放n,n-1個數填滿sum }