<span style="font-family: Arial; ">第21題(數組)</span>
2010年中興面試題編程求解:
輸入兩個整數 n 和 m,從數列1,2,3.......n 中 隨意取幾個數,
使其和等於 m ,要求將其中所有的可能組合列出來。
解法一
我想,稍後給出的程序已經足夠清楚了,就是要注意到放n,和不放n個區別,即可,代碼如下:
#include<list>
#include<iostream>
using namespace std;
list<int>list1;
void find_factor(int sum, int n)
{
// 遞歸出口
if(n <= 0 || sum <= 0)
return;
// 輸出找到的結果
if(sum == n)
{
// 反轉list
list1.reverse();
for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)
cout << *iter << " + ";
cout << n << endl;
list1.reverse();
}
list1.push_front(n); //典型的01揹包問題
find_factor(sum-n, n-1); //放n,n-1個數填滿sum-n
list1.pop_front();
find_factor(sum, n-1); //不放n,n-1個數填滿sum
}
int main()
{
int sum, n;
cout << "請輸入你要等於多少的數值sum:" << endl;
cin >> sum;
cout << "請輸入你要從1.....n數列中取值的n:" << endl;
cin >> n;
cout << "所有可能的序列,如下:" << endl;
find_factor(sum,n);
system("pause");
return 0;
}
解法二
@zhouzhenren:
這個問題屬於子集和問題(也是揹包問題)。本程序採用 回溯法+剪枝
X數組是解向量,t=∑(1,..,k-1)Wi*Xi, r=∑(k,..,n)Wi
若t+Wk+W(k+1)<=M,則Xk=true,遞歸左兒子(X1,X2,..,X(k-1),1);否則剪枝;
若t+r-Wk>=M && t+W(k+1)<=M,則置Xk=0,遞歸右兒子(X1,X2,..,X(k-1),0);否則剪枝;
本題中W數組就是(1,2,..,n),所以直接用k代替WK值。
代碼編寫如下:
//copyright@ 2011 zhouzhenren
//輸入兩個整數 n 和 m,從數列1,2,3.......n 中 隨意取幾個數,
//使其和等於 m ,要求將其中所有的可能組合列出來。
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
/**
* 輸入t, r, 嘗試Wk
*/
void sumofsub(int t, int k ,int r, int& M, bool& flag, bool* X)
{
X[k] = true; // 選第k個數
if (t + k == M) // 若找到一個和爲M,則設置解向量的標誌位,輸出解
{
flag = true;
for (int i = 1; i <= k; ++i)
{
if (X[i] == 1)
{
printf("%d ", i);
}
}
printf("/n");
}
else
{ // 若第k+1個數滿足條件,則遞歸左子樹
if (t + k + (k+1) <= M)
{
sumofsub(t + k, k + 1, r - k, M, flag, X);
}
// 若不選第k個數,選第k+1個數滿足條件,則遞歸右子樹
if ((t + r - k >= M) && (t + (k+1) <= M))
{
X[k] = false;
sumofsub(t, k + 1, r - k, M, flag, X);
}
}
}
void search(int& N, int& M)
{
// 初始化解空間
bool* X = (bool*)malloc(sizeof(bool) * (N+1));
memset(X, false, sizeof(bool) * (N+1));
int sum = (N + 1) * N * 0.5f;
if (1 > M || sum < M) // 預先排除無解情況
{
printf("not found/n");
return;
}
bool f = false;
sumofsub(0, 1, sum, M, f, X);
if (!f)
{
printf("not found/n");
}
free(X);
}
int main()
{
int N, M;
printf("請輸入整數N和M/n");
scanf("%d%d", &N, &M);
search(N, M);
return 0;
}
源網址:http://blog.csdn.net/v_JULY_v/article/details/6419466