POJ-1742Coins

代码:

方法一:

这个是根据完全背包的思路来做,但是加了对个数的限制。

#include<iostream>
#include<stdio.h>
#include<string.h> 
using namespace std;
const int maxn = 1e5+10;
int dp[maxn];
int sum[maxn];
int main(){
    int n,m;
    while(cin>>n>>m&&n&&m){
        int a[n+1],c[n+1];
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&c[i]);
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        int ans = 0;
        for(int i=1;i<=n;i++){
            memset(sum,0,sizeof(sum));
            for(int j=a[i];j<=m;j++){
                if(!dp[j]&&dp[j-a[i]]&&(sum[j-a[i]]<c[i])){//这里很巧妙
                    dp[j] = 1;//做标记
                    sum[j] = sum[j-a[i]]+1;//计数
                    ans++;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

 方法二:

这里用到二进制的性质

例如 有11 个2的话,我们依次存进cnt中 1*2 , 2*2,4*2,4*2;

即11 被分解为 1 2  4  4

这4个数能任意组合成1~11中的每一个数,利用这一性质就可以把时间复杂度降下来,O(n)->O(logn)

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn = 101;
int cnt[1001];
int main(){
    int n,m;
    while(cin>>n>>m&&n&&m){
        int a[maxn];
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int num;
        int len=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&num);
            int m = 1;
            while(m<num){
                cnt[len++] = m*a[i];
                num = num-m;
                m<<=1;
            }
            cnt[len++] = num*a[i];
        }
        bool dp[100000];
        memset(dp,false,sizeof(dp));
        dp[0] = true; 
        for(int i=0;i<len;i++){
            for(int j=m;j>=cnt[i];j--){
                if(!dp[j])
                    dp[j] = dp[j-cnt[i]];
            }
        }
        int ans = 0;
        for(int i=1;i<=m;i++){
            if(dp[i]) ans++;
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

posted @ 2020-02-21 14:54  sqsq  阅读(138)  评论(0编辑  收藏  举报