zoukankan      html  css  js  c++  java
  • Banknotes

    https://loj.ac/problem/10179

    题目描述

      有(n)中面值的硬币,每种硬币有一定的数量,求凑出面值(k)最少要多少枚硬币。

    思路

      首先比较显然的是我们可以写出一个(O(n·k·c_{max})),我们考虑暴力枚举每(i)种硬币的个数,第一维枚举钱数即可。这样理论实践复杂度肯定过不去,我们需要进行优化。考虑一下对于当前枚举的钱数(v),显然如果(k)时可取的,(k+v)也是可取的,显然会用其中代价较小的进行更新,所以我们可以第二维暴力枚举余数,对于当前余数,如果要更新(i),显然是由(i-b[i]*c[i]sim i)同余数的最小的那个,为了使得每一个数都在“同一起跑线”上,我们需要先减去两两之间差的代价。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    int read()
    {
    	int res=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    	return res*w;
    }
    
    int b[220],c[220],q[20020],pos[20020],f[20020];
    int main()
    {
    	int n=read();
    	for(int i=1;i<=n;i++)
    		b[i]=read();
    	for(int i=1;i<=n;i++)
    		c[i]=read();
    	int k=read();
    	memset(f,0x3f,sizeof(f));
    	f[0]=0;
    	for(int i=1;i<=n;i++){//cout<<i<<':'<<endl;
    		for(int j=0;j<b[i];j++)
    		{
    			int head=0,tail=0;
    			q[head]=0x3f3f3f3f;
    			for(int p=j;p<=k;p+=b[i])
    			{
    				int v=f[p]-p/b[i];
    				while(head<=tail&&pos[head]<p-c[i]*b[i])head++;
    				while(head<=tail&&q[tail]>=v)tail--;
    				q[++tail]=v;pos[tail]=p;
    				f[p]=min(f[p],q[head]+p/b[i]);
    //				cout<<p<<' '<<f[p]<<endl;
    			}
    		}
    	}
    	printf("%d
    ",f[k]);
    }
    
  • 相关阅读:
    个人博客开发之blogapi项目统一结果集api封装
    个人博客开发之blogapi 项目整合JWT实现token登录认证
    C语言I博客作业06
    C语言l博客作业03
    C语言I博客作业04
    C语言I博客作业05
    C语言I博客作业01
    C语言I博客作业07
    C语言I博客作业02
    UVA 11427 Expect the Expected [概率]
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11851972.html
Copyright © 2011-2022 走看看