Gold coin (coin) HGOI problem solution

Topic description

  • People on Treasure Island use gold coins, each with a face value of A1; A2; A3; : : : ; An yuan. One day Tony decides to buy a very good watch at a
    nearby store, he wants to pay without change, but he finds that
    the amount of each gold coin in his wallet is only C1; C2; C3; : : : ; Cn indivual. However, Tony knew that the price of the watch would not exceed M gold coins
    (he did not know the exact price of the watch). I don't know if his payment method will work.

  • Your task is to help Tony figure out exactly how many prices the gold coins in his
    wallet .

input format

  • The input includes multiple sets of test data. The format of each set of test data is as follows:
  • The first line contains 2 integers n; M.
  • The second line contains the 2n integers A1; A2; A3; : : : ; An and C1; C2; C3; : : : ; Cn.
  • The last row of the test data has 2 0s, and this row does not need to be processed.

output format

Each set of test data outputs one line, which is an integer, that is, the exact number of prices that can be paid.

Data size and convention

  • For 30% of the data, 1<=N<=30; 1<=M<=1000
  • For 60% of the data, 1<=N<=60
  • For 100% data, 1<=n<=100; 1<=M<=10^5 1<=Ai<=105; 1<=Ci<=1000

answer

  • Since the amount of data is too large (if you try to enumerate the complexity of n*m*Ci), it will definitely time out, and you need to compress.
  • If it is transformed into a simple 0-1 knapsack problem, the time complexity is arbitrarily (O)n*m*Ci, and the space complexity is m(∑Ci).
  • If a rolling array is used, the space complexity can be reduced to m, but the time will still explode.
  • Therefore, binary conversion size compression is required. Example: 13=1+2+4+6; in the previous (1+2+4), the enumeration of all cases from 1 to 7 can be realized, and the occurrence of repeated amounts can be minimized.
 for (int j=temp;j<temp+(int)(log(a[i].C)/log(2));j++) {
    aa[j]=a[i].A*(1<<(j-temp));
  • 是进行对于重复多次相同金额的压缩。时间复杂度降为(O)m∑log2(Ci)。

直接上代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define INF 0x7f7f7f
using namespace std;
int m,n;
void f(){
    freopen("coin.in","r",stdin);
    freopen("coin.out","w",stdout);
}
struct node{
    int A,C;
}a[101];
int dp[100001],aa[100001];
bool check(int a,int b){
    return a>b;
}
int main(){
    f();
    while(cin>>n>>m&&(n!=0&&m!=0)){
        memset(dp,-INF,sizeof(dp));//初始化无限小
        memset(aa,0,sizeof(aa));
        int sum=0,t=1,ans=0;
        for (int i=1;i<=n;i++) {
            cin>>a[i].A;
        }
        dp[0]=0;
        for (int i=1;i<=n;i++) {
            cin>>a[i].C;
            sum+=a[i].C*a[i].A;
            int temp=t,ss=0;
            for (int j=temp;j<temp+(int)(log(a[i].C)/log(2));j++) {
                aa[j]=a[i].A*(1<<(j-temp));//进行二进制左移
                ss+=1<<(j-temp);
                t++;
            }
            if(ss<a[i].C) aa[t++]=a[i].A*(a[i].C-ss);//最后多余为a[i].C-ss单独拿出放在最后
        }
        for (int i=1;i<t;i++){
            for (int j=m;j>=aa[i];j--){
                dp[j]=max(dp[j],dp[j-aa[i]]+1);//0-1背包问题
            }
        }
        for (int i=1;i<=m;i++) if(dp[i]>0) ans++;//最后统计结果
        cout<<ans<<'\n';
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324648335&siteId=291194637