题意:我现在要从ATM中取钱,(ATM机中能取出的钱数最多为M)ATM里面有若干种货币,每一种都有对应的货币面额和张数。
问现在ATM能够取出来的 小于等于M的最大金额。
分析:若将M理解为背包体积(V ),而每种货币的面额理解成 value,货币的面额同样理解成cost,那么这个问题就是一个多重背包问题。
#include <stdio.h>
#include <limits.h>
#define MAX_CASH 100000
#define N 10
#define max(a,b) ((a)>(b)?(a):(b))
int V ;
int n ;
int dp[MAX_CASH+5] ;
int spend[N+5] ;
int sum[N+5] ;
void Restart_DP ( )
{
int i ;
for ( i = 0 ; i <= V ; i ++ )
{
dp[i] = 0 ;
}
}
void ZeroOnePack ( int const cost , int const value )
{
int i ;
for ( i = V ; i >= cost ; i -- )
{
dp[i] = max ( dp[i] , dp[i-cost] + value ) ;
}
}
void CompletePack ( int const cost , int const value )
{
int i ;
for ( i = cost ; i <= V ; i ++ )
{
dp[i] = max ( dp[i] , dp[i-cost] + value ) ;
}
}
void MultiplePack ( int const cost , int const value , int amount )
{
if ( amount * cost > V )
{
CompletePack ( cost , value ) ;
}
else
{
int k ;
for ( k = 1 ; k < amount ; k *= 2 )
{
ZeroOnePack ( k * cost , k * value ) ;
amount -= k ;
}
if ( amount ) ;
{
ZeroOnePack ( cost * amount , value * amount ) ;
}
}
}
void DP_Solve ( int const n )
{
int i ;
for ( i = 1 ; i <= n ; i ++ )
{
int value , amount;
value = spend[i] ;
amount = sum[i] ;
MultiplePack ( spend[i] , value , amount ) ;
}
printf ("%d\n" , dp[V] ) ;
Restart_DP ( ) ;
}
int
main ( )
{
while ( EOF != scanf ("%d%d" , & V , & n ) )
{
int i ;
for ( i = 1 ; i <= n ; i ++ )
{
scanf ("%d%d" , & sum[i] , & spend[i] ) ;
}
DP_Solve ( n ) ;
}
return 0 ;
}