这题一开始是在不知道怎么做....最后才发现要分开做啊.....
dp1[j]表示买j块钱的东西用的最少的硬币数量,dp2[j]表示找j快钱用的最少的硬币数量。
一个是多重背包,一个是完全背包.....注意:多重背包要优化,不然会超时......
AC代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
const int MAX = 0x3f3f3f3f;
inline int min( int a, int b ){
return ( a < b ? a : b );
}
int main(){
int N, T;
int number[100], val[100];
int dp1[20001], dp2[20001];
while( scanf( "%d%d", &N, &T ) != EOF ){
for( int i = 0; i < N; i++ ){
cin >> val[i];
}
for( int i = 0; i < N; i++ ){
cin >> number[i];
}
//多重背包
//要优化....不然会超时......
memset( dp1, 0x3f, sizeof( dp1 ) );
dp1[0] = 0;
for( int i = 0; i < N; i++ ){
int k;
for( k = 1; 2 * k - 1 < number[i]; k = k * 2 ){
for( int j = 20000; j >= k * val[i]; j-- ){
dp1[j] = min( dp1[j], dp1[j- k * val[i]] + k );//一定要注意这里是k啊!!!!!!不是1!!!!!!
}
}
k = number[i] - k + 1;
for( int j = 20000; j >= k * val[i]; j-- ){
dp1[j] = min( dp1[j], dp1[j- k * val[i]] + k );//一定要注意这里是k啊!!!!!!不是1!!!!!!
}
}
//完全背包
memset( dp2, 0x3f, sizeof( dp2 ) );
dp2[0] = 0;
for( int i = 0; i < N; i++ ){
for( int j = val[i]; j <= 20000; j++ ){
dp2[j] = min( dp2[j], dp2[j-val[i]] + 1 );
}
}
int ans = MAX;
for( int i = 0; T + i <= 20000; i++ ){
if( dp1[T+i] != MAX && dp2[i] != MAX ){
ans = min( ans, dp1[T+i] + dp2[i] );
}
}
if( ans < MAX ){
cout << ans << endl;
}else{
cout << -1 << endl;
}
}
return 0;
}