硬币问题:
1:原始的多重背包 tle
#include<bits/stdc++.h>
using namespace std;
int dp[105][100005];
int n;
int w[105],c[105];
int main(){
int m;
while(cin>>n>>m,n||m) {
::memset(dp,0,sizeof dp);
for (int i = 1; i <= n; ++i) {
cin >> c[i];
}
for (int i = 1; i <= n; ++i) {
cin >> w[i];
dp[i][w[i]] = 1;
}
for (int i = 2; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
for (int k = 0; k <= c[i] && k * w[i] <= j; ++k) {
if (dp[i - 1][j] == 1)
dp[i][j + k * w[i]] = 1;
}
}
}
int cnt = 0;
for (int i = 1; i <= m; ++i) {
if (dp[n][i] == 1)
cnt++;
}
cout << cnt<<endl;
}
}
2://///二进制优化,时间复杂度nlog1000*m,会超时,
#include<iostream>
#include<algorithm>
using namespace std;
#include<vector>
int n,m;
int w[105];
int f[100005];
int v[105];
int main(){
while(cin>>n>>m&&n&&m){
for (int i = 0; i <=m ; ++i) {
f[i]=0;
}
vector< int >a;
for (int i = 1; i <=n ; ++i) {
cin>>w[i];
}
for (int i = 1; i <=n ; ++i) {
cin>>v[i];
}
f[0]=1;
a.push_back(0);
for(int i=1;i<=n;i++){
int k=1;
while(k<=v[i]){
a.push_back(k*w[i]);
v[i]-=k;
k*=2;
}
if(v[i]>0){
a.push_back(v[i]*w[i]);
}
}
f[0]=1;
for (int i = 1; i <a.size() ; ++i) {
for (int j = m; j >=a[i] ; --j) {
if(f[j-a[i]]==1){
f[j]=1;
}
}
}
int cnt=0;
for (int i = 1; i <=m ; ++i) {
if(f[i])cnt++;
}
cout<<cnt<<endl;
}
}
3.正解,时间复杂度是n*m,硬币问题,
- 1.若是j在本i层之前已经被凑出来了,则吧f[j]等于c[i]的数量
- 2.若是j小于w[i]或者f【j-w[i]】没有被凑出来或者已经消耗完了c[i];则为-1
- 3.f【j】由w【i】凑出,就等于f【j-w[i]】减1;
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int f[100005];
int n;
int w[105],c[105];
int main(){
int m;
while(cin>>n>>m,n||m) {
::memset(f,-1,sizeof f);
for (int i = 1; i <= n; ++i) {
cin >> w[i];
}
for (int i = 1; i <= n; ++i) {
cin >> c[i];
}
f[0]=0;
for (int i = 1; i <=n ; ++i) {
for (int j = 0; j <=m ; ++j) {
if(f[j]>=0)f[j]=c[i];
else if(j<w[i]||f[j-w[i]]<=0)f[j]=-1;
else f[j]=f[j-w[i]]-1;
}
}
int cnt=0;
for (int i = 1; i <=m ; ++i) {
if(f[i]>=0)cnt++;
}
cout << cnt<<endl;
}
}