输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 ,使其和等于 m
轉(zhuǎn)載自:http://blog.sina.com.cn/s/blog_7571423b01016707.html
編程求解:輸入兩個(gè)整數(shù) n 和 m ,從數(shù)列 1 , 2 , 3.......n 中隨意取幾個(gè)數(shù) ,使其和等于 m , 要求將其中所有的可能組合列出來(lái).
分析:
???????主要思想:分治,即m=idx+m-idx
???????從最大數(shù)字n開(kāi)始查找,然后逐漸后退,但每次查找只會(huì)在比當(dāng)前數(shù)字大的方向進(jìn)行組合嘗試,這樣可以保證找到的組合不會(huì)重復(fù)。
參考代碼
?
*****************************************************************************
?解題思路:
????顯而易見(jiàn), 當(dāng)n>m時(shí), 肯定存在滿足題目要求的子集. 由于數(shù)列1,2,...,n是正整數(shù)數(shù)列, 這使得所有的大于m的數(shù)加上數(shù)列最小元素1都會(huì)大于m, 所以當(dāng)n>m時(shí)我們只需要考慮子數(shù)列1,2,...,m即可.
?????當(dāng)n<=m時(shí),我們需要搜索1,2,...,n中符合條件的子集. 實(shí)際上, 我們可以將原問(wèn)題分解成兩個(gè)子問(wèn)題:
子問(wèn)題一: 在n個(gè)數(shù)的數(shù)列,我們?nèi), 然后原問(wèn)題就變?yōu)檎页?,2,...,n-1中和為m-n的所有子集,然后將所有的子集都加上元素n就得到了原問(wèn)題的部分解集;
子問(wèn)題二: 我們不取n, 原問(wèn)題就變?yōu)檎页?,2,...,n-1中和為m的所有子集.
聯(lián)合兩個(gè)子問(wèn)題的解, 便得到了原問(wèn)題的解集.
????我們用subsets( n, m) 表示原問(wèn)題, 那么原問(wèn)題可表示為子問(wèn)題 subsets(n-1, m) 和subsets( n-1, m-n)的解集的并集.
????即:???subsets( n, m)??= subsets(n-1, m) U subsets( n-1, m-n)
????實(shí)際中,可采用回溯的方法進(jìn)行求解. 后面附有完整的代碼.
????實(shí)際的搜索方法類似于二叉樹(shù)的方法, 去除不符合條件的解. 例如下面的二叉樹(shù)就表示了1,2,...,n的全組合的求解過(guò)程. 左邊分支表示取,右邊的分支表示舍. 針對(duì)于0-1背包問(wèn)題, 八皇后問(wèn)題, 射擊十次命中九十環(huán)的打法問(wèn)題等等, 則需要剪除掉一些不符合條件的子樹(shù).
?
?
#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;
}
總結(jié)
以上是生活随笔為你收集整理的输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 ,使其和等于 m的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Ubuntu下用eclipse调试caf
- 下一篇: 苹果怎么查询激活时间