硬幣兌換問題的兩種解法之比較

給定一個集合的硬幣面額比如: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

結果對比見下圖:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章