输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 ,使其和等于 m
轉載自:http://blog.sina.com.cn/s/blog_7571423b01016707.html
編程求解:輸入兩個整數 n 和 m ,從數列 1 , 2 , 3.......n 中隨意取幾個數 ,使其和等于 m , 要求將其中所有的可能組合列出來.
分析:
???????主要思想:分治,即m=idx+m-idx
???????從最大數字n開始查找,然后逐漸后退,但每次查找只會在比當前數字大的方向進行組合嘗試,這樣可以保證找到的組合不會重復。
參考代碼
?
*****************************************************************************
?解題思路:
????顯而易見, 當n>m時, 肯定存在滿足題目要求的子集. 由于數列1,2,...,n是正整數數列, 這使得所有的大于m的數加上數列最小元素1都會大于m, 所以當n>m時我們只需要考慮子數列1,2,...,m即可.
?????當n<=m時,我們需要搜索1,2,...,n中符合條件的子集. 實際上, 我們可以將原問題分解成兩個子問題:
子問題一: 在n個數的數列,我們取n, 然后原問題就變為找出1,2,...,n-1中和為m-n的所有子集,然后將所有的子集都加上元素n就得到了原問題的部分解集;
子問題二: 我們不取n, 原問題就變為找出1,2,...,n-1中和為m的所有子集.
聯合兩個子問題的解, 便得到了原問題的解集.
????我們用subsets( n, m) 表示原問題, 那么原問題可表示為子問題 subsets(n-1, m) 和subsets( n-1, m-n)的解集的并集.
????即:???subsets( n, m)??= subsets(n-1, m) U subsets( n-1, m-n)
????實際中,可采用回溯的方法進行求解. 后面附有完整的代碼.
????實際的搜索方法類似于二叉樹的方法, 去除不符合條件的解. 例如下面的二叉樹就表示了1,2,...,n的全組合的求解過程. 左邊分支表示取,右邊的分支表示舍. 針對于0-1背包問題, 八皇后問題, 射擊十次命中九十環的打法問題等等, 則需要剪除掉一些不符合條件的子樹.
?
?
#include <stdio.h>
#include <assert.h>
#include <time.h>
#define MAXN 1000
int stack[MAXN];
int top = -1;
void push( int e )
{
?assert( top < MAXN );
?stack[++top] = e;
}
void pop( )
{
?assert( top > -1 );
?top--;
}
void clear()
{
?top = -1;
}
void printStack( )
{
?int i=top;
?while( i>-1 )
??printf("%d\t", stack[i--] );
?printf("\n");
}
int subsets( int n, int m )
{
?int i;
?int num=0;
?int flag = 1;
?
?if( n > m )
??n = m;
?
?for( i = n; flag && i>=1; i-- )
?{
??
??push( i );
??
??
??if( m-i == 0 )
??{
???num++;
???printStack();
??}
??else
??{
???
???
???if( (i-1)*i/2 < (m-i) )
???{
????pop();
????flag = 0;
????continue;
???}
???
???num += subsets( i-1, m-i );
??}
??
??
??pop();
?}?
?return num;
}
void testSubsets()
{
?assert( 1 == subsets( 1, 1 ) );
?printf( "\n\n" );
?assert( 0 == subsets( 1, 2 ) );
?printf( "\n\n" );
?assert( 3 == subsets( 5, 6 ) );
?printf( "\n\n" );
?assert( 5 == subsets( 7, 7 ) );
}
int main()
{
?testSubsets( );
?clock_t start = clock();
?subsets( 50, 50 );
?clock_t duration = clock() - start;
?printf("it takes %d seconds\n", duration/CLOCKS_PER_SEC );
?return 0;
}
總結
以上是生活随笔為你收集整理的输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 ,使其和等于 m的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu下用eclipse调试caf
- 下一篇: Fine-tunning适用情况