经典问题,给定一些面额的纸币,和要找回金币的总额,找出使得纸币数量最少的方案
今天第一次写 Java, 开始 Java 学习之旅吧
public class Make_Change {
public static void main ( String[] args ) {
final int [] Value = new int[] { 1 , 2 , 5 , 10 , 20 , 50 } ;
final int money = 100 ;
int [] dp = new int[money + 1] ;
make_change ( money , Value , dp ) ;
}
public static void make_change ( final int money , final int [] Value , int [] dp ) {
int [] pre = new int[money + 1] ;
for ( int i = 1 ; i <= money ; ++i ) {
int ans = i ;
for ( int j = 0 ; j < Value.length ; ++j ) {
if ( i >= Value[j] ) {
int temp = dp[i - Value[j]] + 1 ;
if ( ans > temp ) {
ans = temp ;
pre[i] = i - Value[j] ;
}
}
}
dp[i] = ans ;
System.out.print ( "面值为 " + i + " 的最少找钱数是 " + ans + "\t" ) ;
int des = i ;
while ( pre[des] != 0 ) {
System.out.print ( des - pre[des] + " " ) ;
des = pre[des] ;
}
System.out.println ( des ) ;
}
}
}
主要是如何保存最优的方案:
思路就是设置一个 pre 数组,因为最优解一定可以分解成某个小于自己的最优解加上某个 零钱 ,
所以,尝试每个硬币,如果在前面最优解的基础上,加上这个硬币更优,就把这个前面最优解的下标 i - Value[i] 记下来,要输出方案时,就输出 i - ( i - Value[i] ) = Value[i].
运行结果 :
还有一种更麻烦的思路,就是用一个 vector 二维数组保存每个点所记录的最优解方案,发现前面最优解加上某个零钱更优,就把最优解替换成前面最优解的 vector 的内容,然后 push_back 当前加入的零钱、
#include <bits/stdc++.h>
using namespace std ;
int dp[1005] ;
vector < int > Vec[1005] ;
int main () {
const vector < int > One = { 1 , 2 , 5 , 10 , 20 , 50 } ;
const int money = 100 ;
for ( int i = 1 ; i <= money ; ++i ) {
int ans = i ;
for ( const auto it : One ) {
if ( i >= it ) {
int temp = dp[i - it] + 1 ;
if ( ans > temp ) { // 只能保存一组解
ans = temp ;
Vec[i].clear () ;
for ( const auto j : Vec[i - it] )
Vec[i].push_back ( j ) ;
Vec[i].push_back ( it ) ;
}
}
}
dp[i] = ans ;
cout << "面值为 " << i << " 找钱数 : " << ans << "\t" ;
for ( const auto it : Vec[i] )
cout << it << " " ;
cout << endl ;
}
return 0 ;
}