• 一本通1601【例 5】Banknotes


    1601:【例 5】Banknotes

    时间限制: 1000 ms         内存限制: 524288 KB

    【题目描述】

    原题来自:POI 2005

    Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有 n 种面值的硬币,面值分别为 b1,b2,,bn。但是每种硬币有数量限制,现在我们想要凑出面值 k,求最少要用多少个硬币。

    【输入】

    第一行一个数 n;

    接下来一行 n 个整数 b1,b2,,bn

    第三行 n 个整数 c1,c2,,cn ,表示每种硬币的个数;

    最后一行一个数 k,表示要凑的面值数。

    【输出】

    第一行一个数表示最少需要付的硬币数。

    【输入样例】

    3
    2 3 5
    2 2 1
    10

    【输出样例】

    3

    【提示】

    数据范围与提示:

    对于全部数据,1n200,1b1<b2<<bn2×104,1ci,k2×104 。

    sol:比较裸的完全背包??可以有两种优化:

    二进制优化太水不说了

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-');
            ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48);
            ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');
            return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    inline void writeln(ll x)
    {
        write(x);
        putchar('
    ');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) writeln(x)
    const int N=20005,M=2000005;
    int n,m,B[N],C[N],dp[M];
    int main()
    {
        int i,j,k;
        R(n);
        for(i=1;i<=n;i++) R(B[i]);
        for(i=1;i<=n;i++) R(C[i]);
        R(m);
        memset(dp,63,sizeof dp);
        dp[0]=0;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=C[i]&&j*B[i]<=m;j<<=1)
            {
                for(k=m;k>=j*B[i];k--) dp[k]=min(dp[k],dp[k-j*B[i]]+j);
            }
        }
        Wl(dp[m]);
        return 0;
    }
    /*
    input
    3
    2 3 5
    2 2 1
    10
    output
    3
    
    input
    10
    6 17 111 249 250 495 496 497 498 499
    100 100 100 100 1 100 100 100 100 100
    500
    output
    6
    
    input
    3
    300 700 4800
    10000 10000 10000
    5000
    output
    10
    */
    二进制优化

    单调队列优化:对于模Bi相同的几个权值之间的dp转移,可以用单调队列优化,令权值V=j+k*Bi,dp[V]=min(dp[V],dp[j+k'*Bi]+k-k‘),所以可以用dp[j+k*Bi]-k最小为队首的单调队列来优化成n*m,(细节:为了防止被反复统计,应该先插入当前节点再更新当前节点的dp值)

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-');
            ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48);
            ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');
            return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    inline void writeln(ll x)
    {
        write(x);
        putchar('
    ');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) writeln(x)
    const int N=205,M=20005;
    int n,m,B[N],C[N],dp[M];
    struct Data
    {
        int Shuz,Weiz;
    }Ddq[M];
    int main()
    {
        int i,j,k;
        R(n);
        for(i=1;i<=n;i++) R(B[i]);
        for(i=1;i<=n;i++) R(C[i]);
        R(m);
        memset(dp,63,sizeof dp);
        dp[0]=0;
        for(i=1;i<=n;i++)
        {
            for(j=0;j<B[i];j++)
            {
                int Head=1,Tail=0;
                for(k=0;;k++)
                {
                    int x=k*B[i]+j; if(x>m) break;
                    while(Head<Tail&&Ddq[Head].Weiz<k-C[i]) Head++;
                    while(Head<=Tail&&dp[x]-k<Ddq[Head].Shuz-Ddq[Head].Weiz) Tail--;
                    Ddq[++Tail]=(Data){dp[x]-k,k};
                    dp[x]=min(dp[x],Ddq[Head].Shuz+k);
                }
            }
        }
        Wl(dp[m]);
        return 0;
    }
    /*
    input
    3
    2 3 5
    2 2 1
    10
    output
    3
    */
    单调队列优化
  • 相关阅读:
    C++——文件的读写
    我以我血荐轩辕——记徐家福教授的演讲
    文件命名
    面向对象
    关于函数
    php跨域发送请求原理以及同步异步问题
    关于iframe
    关于url
    cookie
    call和apply
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10371987.html
Copyright © 2020-2023  润新知