给定一个集合的硬币面额比如:int coin[] = {1, 2, 3, 4, 5, 6, 8},并且假定每个面额的硬币个数无限多;再给定一定面额的纸币比如100,求解共有多少种兑换法?
这个问题常用两种解法,一个是递归搜索,一个是动态规划,下面分别列举之:
//code as following #ifndef COIN_CHANGE_H #define COIN_CHANGE_H #include<string.h> #include<assert.h> #include<windows.h> // recursive search template<class T> unsigned long ImplCoinChange( T* items, int curIdx, int sum ) { if(0 == sum ) { return 1; } if(sum < 0 ) { return 0; } if(curIdx < 0 && sum > 0 ) { return 0; } return ImplCoinChange( items, curIdx, sum - items[curIdx] ) + ImplCoinChange( items,curIdx - 1, sum ); } //release memory template<class T> void Release( T** items, int size ) { for(int i = 0; i < size; i++ ) { if(items[i] ) { delete[] items[i]; items[i]= 0; } } if(items ) { delete[] items; } } // dynamic programming state change equation table[sum][curidx] = table[sum -item[curidx]][curidx] + table[sum][curidx - 1] // represent select th coin idx and not select template<class T> unsigned long ImplCoinChangeDP( T* items, int itemSize, int sum ) { int** table = new int*[sum + 1]; for(int i = 0; i <= sum; i++ ) { table[i] = new int[itemSize + 1]; memset(table[i], 0x00, sizeof(int) * ( itemSize + 1)); } for(int i = 0; i <= itemSize; i++ ) { table[0][i] = 1; int x = 0; int y = 0; for( int i = 1; i <= sum; i++ ) { for(int j = 0; j < itemSize; j++ ) { if(i >= items[j] ) { x = table[i - items[j]][j]; } else { x = 0; } if(j > 0 ) { y = table[i][j-1]; } else { y = 0; } table[i][j] = x + y; } } int res = table[sum][itemSize - 1]; Release(table, itemSize + 1 ); return res; } } //unit test class, it can be used to record test iput and output typedef struct tagTestCase { int* coin; int size; int sum; unsigned long consumeTimeFirst; unsigned long consumeTimeSecond; unsigned long resCount; tagTestCase():coin(0),size(0), sum(0), consumeTimeFirst(0),consumeTimeSecond(0), resCount(0) { } tagTestCase(int seed ):coin(0),sum(0), size(seed), consumeTimeFirst(0),consumeTimeSecond(0),resCount(0) { GenerateCoin(seed ); } tagTestCase(int seed, int _sum ):coin(0), sum(_sum), size(seed), consumeTimeFirst(0),consumeTimeSecond(0), resCount(0) { GenerateCoin(seed ); } tagTestCase(int* item, int itemSize, int _sum ): coin(0), sum(_sum), size(0), consumeTimeFirst(0),consumeTimeSecond(0), resCount(0) { GenerateCoin(itemSize, item ); } ~tagTestCase() { Remove(); } void SetTestState( int seed, int _sum ) { sum = _sum; GenerateCoin(seed ); } void Remove() { if(coin ) { delete[] coin; coin= 0; } } void GenerateCoin(int seed, int* item = 0) { assert(seed > 0 ); Remove(); coin = new int[seed]; if(item != 0 ) { memcpy(coin, item, sizeof(int)*seed); } else { for(int i = 0; i < seed; i++ ) { coin[i]= i + 1; } } size = seed; } }TestCase, *pTestCase; // implementate test case void ImplTestCase( TestCase& testCase ) { unsigned long firstStart = GetTickCount(); testCase.resCount= ImplCoinChange( testCase.coin, testCase.size - 1, testCase.sum ); unsigned long firstEnd = GetTickCount(); testCase.consumeTimeFirst= firstEnd - firstStart; int newCount= ImplCoinChangeDP( testCase.coin, testCase.size, testCase.sum ); testCase.consumeTimeSecond= GetTickCount() - firstEnd; printf("recursivesearch and dynamic programming time is %d and %d\n", testCase.consumeTimeFirst,testCase.consumeTimeSecond ); } void UnitTest( int nums, int sumbase, int seedbase ) { assert(nums > 0 ); int* sum = new int[nums]; for(int i = 0; i < nums; i++ ) sum[i]= sumbase + i; pTestCase test = new TestCase[nums]; for(int i = 0; i < nums; i++ ) { test[i].SetTestState(seedbase * ( i + 1), sum[i] ); ImplTestCase(test[i] ); } } void TestCoinChange( ) { int nums = 10; int sumbase = 50; int seedbase = 5; UnitTest(nums, sumbase, seedbase ); }
编译环境:vs2005
结果对比见下图: