zoukankan      html  css  js  c++  java
  • 《算法竞赛进阶指南》0x52背包DP POJ1742Coins

    题目链接:http://poj.org/problem?id=1742

    多重背包优化,给出若干面值硬币,和他们的数量,现在问1-m之间有多少数量是可以通过他们拼出的,复杂度需要控制,而且常数不能大。

    解法非常巧妙,用g数组存上一个1离当前位置的距离,实际上这个问题是一个滑动窗口的问题,对于第i个面值,窗口的长度是数量+1,分别覆盖了j,j-v,j-2*v...j-s*v。如果在这个窗口之中有一个1,那么f[j]就是1,否则f[j]就是0,对第i个数之前可拼接的数进行操作,判断距离是否合适即可判断是否能拼出当前的数。

    思路非常具有创新性,朴素的算法和二进制优化以及队列优化都是没法过的。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring> 
    using namespace std;
    const int maxn = 110,maxm = 100010;
    int f[maxm],g[maxm];
    int a[maxn],c[maxn];
    int n,m;
    int main(){
        while(scanf("%d%d",&n,&m),n||m){
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            for(int i=1;i<=n;i++)scanf("%d",&c[i]);
            memset(f,0,sizeof f);
            f[0]=1;
            for(int i=1;i<=n;i++)
            {
                for(int j=0;j<=m;j++)g[j]=0;
                for(int j=a[i];j<=m;j++){
                    if(!f[j] && f[j-a[i]] && g[j-a[i]]<c[i]){
                        f[j]=1;
                        g[j]=g[j-a[i]]+1;
                    }
                }
            }
            int ans=0;
            for(int i=1;i<=m;i++)ans+=f[i];
            cout<<ans<<endl;
        }
    }
  • 相关阅读:
    Educational Codeforces Round 58
    Educational Codeforces Round 59
    Codeforces Round #534 (Div. 2)
    Codeforces Round #531 (Div. 3)
    Codeforces Round #536 (Div. 2)
    Codeforces Round #530 (Div. 2)
    Codeforces Round #533 (Div. 2)
    Codeforces Round #535 (Div. 3)
    Codeforces Round #532 (Div. 2)
    Codeforces Round #538 (Div. 2)
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13402593.html
Copyright © 2011-2022 走看看