BootStar

Just For Dream

uva:674 - Coin Change

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=114&page=show_problem&problem=615

题目大意:有五个数,分别为:1 , 5 , 10 , 25  , 50 ,对于任意输入的一个正整数n , n由其中的一个或者多个数组合累加得到,求有多少种方法。例如:11可以由11个1组成,也可以由6个1一个5组成,还可以有一个10 ,一个1组成,或者2个5和一个1,一共有4种方法.

开始的时候想用一个一维数组来表示,对应的数n的可能组成方式个数,状态转移的时候发现有大量的重复,这样求出的结果中有很多的重复。开一个二维数组来表示,横向表示,用前j个数,可能的组成方式个数,这样状态转移的时候就不会出现重复了。

 设num[i][j] 表示整数i有前j个数的组成的所有可能情况。

num[i][j] = num[ i - data [ j ] ] [ j ]  ( i / data [ j ] > 0 )  &&  num [ i ] [ j ] += num[ i ] [ j - 1 ]  ( j  >  0 ) 

源代码:

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

using namespace std;
const int maxn = 7500 ;

int num[maxn][6];
int data[] ={1 , 5 , 10 , 25 , 50} ;

int n ;

int main()
{
//	freopen("in.txt" , "r" , stdin);
	int i ;
	int j ;

	memset(num , 0 , sizeof(num));
	num[0][0] = 1 ;

	for(i = 0 ; i <= 7500 ; i ++)
	{
		for(j = 0 ; j < 5 ; j ++)
		{
			if(i/data[j])
			{
				num[i][j] = num[i-data[j]][j]  ;
			}
			if(j > 0)
				num[i][j] += num[i][j-1] ;
		}
	}

	while(cin>>n)
	{
		printf("%d\n" , num[n][4]) ;
	}
    return 0;
}

补充 ,在用递推的方式AC后, 又用记忆化搜索的方式试了下,代码如下:

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

using namespace std ;

const int maxn = 7500 ;
int  data[] = { 1 , 5 , 10 , 25 , 50} ;

int num[maxn][5] ;
int dp(int  , int ) ;

int n ;

int main()
{
	//freopen("in.txt" , "r" , stdin) ;
	memset(num , 0 , sizeof(num)) ;
	while(cin>>n)
	{
		cout<<dp(4 , n)<<endl ;
	}
	return 0 ;
}

int dp(int layer , int s)
{
	if( s == 0)
		return 1 ;
	int & ans = num[s][layer] ;

	if(ans > 0)
		return ans ;

	if(s >= data[layer])
		ans += dp(layer , s - data[layer]) ;
	if(layer > 0)
		ans += dp(layer - 1 , s ) ;
	return ans ;
}



阅读更多
文章标签: layer
个人分类: 动规 uva
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

uva:674 - Coin Change

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭