下面是一個詳細的解決方案。對於給定的數據,它會生成:
Data (6): 3 2 4 1 1 9
Found: 3 + 2 = 5
Found: 3 + 1 + 1 = 5
Found: 4 + 1 = 5
Found: 4 + 1 = 5
關鍵是要了解需要哪些數據來解決問題。你需要知道:
- 目標總
- 數量和未選中的元素列表(迄今爲止的元素之和)
- 列表
的數量和已元素列表
'到目前爲止'可以從列表中已經存在的元素的數量和列表中派生出來,但是傳遞它也很方便。這給出了一個6參數遞歸函數。它被調用期望的目標,到目前爲止的總和爲0,要搜索的元素的完整數組,以及足夠大的空列表以容納要搜索的所有元素。這發生在main()
。該函數標識是否找到任何添加到目標的列表(如果不是,則返回0,如果是,則返回1),因此測試和報告以及main()
的結束。
在該功能中,檢查各種不可能的條件並進行救援。如果在頂部使用debug = 1
進行編譯,則打印該函數的入口數據。掃描剩餘的未經檢查的元素,檢測元素何時使得總和等於目標並報告這樣做的列表(注意,它丟失了原始索引信息;可以添加該元素,但它是讀者的練習)。如果元素足夠小以便爲另一個元素留出空間,請將該元素添加到找到的列表中,並將該數組的其餘部分傳遞給該函數的遞歸調用。其他功能是簡單的打印循環。
當目標被設定爲40(而不是5),它可以正確地報告沒有亞羣被發現將高達40
有可能是更容易的方式編寫它,但我病理反對不必要的全局變量(我認爲debug
是一種有條件地編譯代碼而不是作爲全局變量的方式)。可以將參數列表打包在一個結構中;不過,我不確定這會有多大幫助。如果我包括<stdbool.h>
,我可以使用bool
而不是int
(和false
和true
而不是0
和1
)。該代碼是無悔的C99或C11;它不會像在C89下編寫的那樣編譯(但是它不會很難與C89一起使用)。
代碼:
#include <stdio.h>
static const int debug = 0;
static void found_one(int num, int *list)
{
printf("Found: ");
char const *pad = "";
int sum = 0;
for (int i = 0; i < num; i++)
{
printf("%s%d", pad, list[i]);
pad = " + ";
sum += list[i];
}
printf(" = %d\n", sum);
}
static void print_array(char const *tag, int num, int *arr)
{
printf("%s (%d):", tag, num);
for (int i = 0; i < num; i++)
printf(" %d", arr[i]);
putchar('\n');
}
static int find_subsets(int target, int sumsofar, int num_src, int *src,
int num_dst, int *dst)
{
if (sumsofar >= target)
return 0;
if (num_src <= 0)
return 0;
if (debug)
{
printf("-->> %s: sumsofar = %d, num_src = %d, num_dst = %d\n",
__func__, sumsofar, num_src, num_dst);
print_array("Source", num_src, src);
print_array("Dest'n", num_dst, dst);
}
int rc = 0;
int max = target - sumsofar;
for (int i = 0; i < num_src; i++)
{
if (src[i] == max)
{
dst[num_dst] = src[i];
found_one(num_dst + 1, dst);
rc = 1;
}
else if (src[i] < max)
{
dst[num_dst] = src[i];
if (find_subsets(target, sumsofar + src[i], num_src - (i + 1),
src + (i + 1), num_dst + 1, dst))
rc = 1;
}
}
if (debug)
printf("<<-- %s: %d\n", __func__, rc);
return rc;
}
int main(void)
{
int data[] = { 3, 2, 4, 1, 1, 9 };
enum { NUM_DATA = sizeof(data)/sizeof(data[0]) };
int subset[NUM_DATA];
int target = 5;
print_array("Data", NUM_DATA, data);
if (find_subsets(target, 0, NUM_DATA, data, 0, subset) == 0)
printf("Did not find any subsets totalling %d\n", target);
return 0;
}