1. 程式人生 > >輸入兩個整數n 和m,從數列1,2,3.......n 中隨意取幾個數, 使其和等於m ,要求將其中所有的可能組合列出來

輸入兩個整數n 和m,從數列1,2,3.......n 中隨意取幾個數, 使其和等於m ,要求將其中所有的可能組合列出來

中興面試題之一,難度係數中。

題目描述如下:輸入兩個整數n 和m,從數列1,2,3.......n 中隨意取幾個數,
使其和等於m ,要求將其中所有的可能組合列出來。

邏輯分析:

1、比起微軟,google,百度這些公司,中興的面試題還是略顯逗比的,並非是說難度上差異,而是中興的題目總是顯得不倫不類。本題其實就是考察數的組合,對於此類問題,通常手段都是遞迴,而我們的目標就在於找出遞迴式。

2、問題其實本質上就是0/1揹包問題,對於每一個n,我們採用貪婪策略,先考察是否取n,如果取n,那麼子問題就變成了find(n-1,m-n),而如果捨棄n,子問題則為find(n-1,m)。至此,我們利用DP思想找到了遞迴式(很多時候,所謂動態規劃,貪婪只是一念之差)。

3、那麼,如何制定解的判定策略?我們知道,遞迴需要邊界條件,而針對揹包問題,邊界條件只有兩種,如果n<1或者m<1,那麼便相當於“溢位”,無法combo出m,而另一種可能就是在剩餘的n個裡恰好滿足m==n,即此時 揹包剛好填充滿,輸出一組解單元。除此之外,再無其他。

C原始碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int length;

void findCombination(int n,int m,int *flag)
{
	if(n < 1 || m < 1)
		return;
	if(n > m)
		n = m;
	if(n == m)
	{
		flag[n-1] = 1;
		for(int i=0;i<length;i++)
		{
			if(flag[i] == 1)
				printf("%d\t",i+1);
		}
		printf("\n");
		flag[n-1] = 0;
	}
	flag[n-1] = 1;
	findCombination(n-1,m-n,flag);
	flag[n-1] = 0;

	findCombination(n-1,m,flag);
}

int main()
{
	int n, m;
	scanf("%d%d",&n,&m);
	length = n;
	int *flag = (int*)malloc(sizeof(int)*length);
	findCombination(n,m,flag);
	free(flag);
	return 0;
}

注:我們設定flag揹包,用來標註對應的n+1是否被選中,1表示被選中,0則表示未選中,每當滿足m==n時,則輸出一組解。程式容易產生邏輯bug的地方在於length的使用(讀者可以思考一下為何需要全域性變數length,而不是直接使用n來代替for迴圈)。