给定一个集合的硬币面额比如: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
结果对比见下图:

硬币找零算法
本文介绍了一种经典的组合数学问题——硬币找零问题,并提供了两种解决方案:递归搜索和动态规划。通过对比两种方法的运行时间,展示了动态规划在解决此类问题上的效率优势。
666

被折叠的 条评论
为什么被折叠?



