方法一:遞歸code
從1~n中,取數,使其和爲sum。遞歸
list<int> list1; void SumOfkNum( int sum, int n){ if( n<=0 || sum<=0) return; if( sum==n){ list1.reverse(); //output from min_value for( list<int>::iterator iter = list1.begin(); iter!=list1.end(); iter++) cout<<*iter<<"+"; cout<<n<<endl; list1.reverse(); //recover } list1.push_front( n); SumOfkNum( sum-n, n-1); list1.pop_front( n); SumOfkNum( sum, n-1); }
方法二:回溯it
t = Σ(1,...,k-1)WiXi, r = Σ(k,...,n)Wiclass
W={ 1, 2, ..., n}, 因此 Wk=k。t爲已求和,Wi表示第i件物品的價值, Xi表示添加第 i件物品的添加數量。咱們這裏由於每一個數只能取一次,因此 Xi 都爲 true或 false。方法
void SumOfkNum( int t, int k, int r, int &m, bool &flag, bool *x){ x[k]=true; //輸入t和r,嘗試Wk if( t+k==M){ //若找到一個和爲m,則設置解向量的標誌位,輸出解 flag = true; for( int i=1; i<=k; ++i) if( x[i] == true) printf("%d ",i); printf("\n"); }else{ //若第k+1個數知足條件,則遞歸左子樹 if( t+k+(k+1) <=m ) SumOfkNum( t+k, k+1, r-k, m, flag, x); //若不選第k個數,選第k+1個數知足條件,則遞歸右子樹 if( (t+r-k >=m) && (t+(k+1)<=m)){ x[k] = false; SumOfkNum( 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/2; if( 1>m || sum<m){ //預先排除無解狀況 printf("not found\n"); return; } bool f = false; SumOfkNum( 0, 1, sum, m, f, x); if( !f) printf("not found\n"); free( x); }