题目链接:http://codeforces.com/problemset/problem/913/C
这道题的主要思想就是贪心,看着非常像DP
以至于我第一次写的时候误认为就是DP,和背包问题差不多
如果用背包的角度来看,背包需要开DP数组,这个数组大小是N x M (n是物品数量,m是容量大小)
这道题容量大小为1e9 明显开不了这么大的数组,虽然n很小,即使简化为一维数组,大小也还是M
此时的我还没有死心.....为什么不能用离散化一下?,但是仔细一想,离散化后数组大小还是不能变.....
好吧 换个思路
为了尽量的节约金钱,肯定是先选性价比高的产品了,那么首先按照性价比排个序,从大到小排序
这样,从第一个开始挑选,这样可以尽量的解决金钱
那么是如何进行挑选的?
1.先按照性价比最高的先装,如果能装满一瓶就继续装,如果不够一瓶,那么就先别装了,因为有可能下一种的饮料虽然性价比不高,但是架不住便宜,而且容量正好可以装剩下的。比如第一种容量为4,价钱为4,第二种容量为1,价钱为2,需要容量为5。有前面这种情况也肯定有装第二种还不如装第一种划算 比如:第一种容量为4,价钱为2,第二种容量为1,价钱为3,需要容量为5,这样答案就不同了。这时我们就要比较一下两种方案
2.会不会出现这种情况?
按照性价比最高的装了n瓶,第二种装了1瓶,但是这并不是最佳情况,第二种只装剩下的,还有很多剩余,并且剩余的容量比第一种的容量还大,这样可以第一种装n-1瓶,剩下的用第二种装,这样岂不是更美滋滋?
比如:第一种容量20,价格10,第二种容量30,价格16,现需要30容量的,如果按照上面的方法肯定是错误!!那么哪里错了???
其实没有错误,不会有这种数据的!!!因为容量必定为2的倍数,换句话说,小容量是大容量的因子。通俗点讲,用多个小容量的可以拼凑出所有的大容量,这就导致,如果 小容量的性价比最高,那么比它容量大的其实都可以不用选,不用看了
正是因为这样,才保证上述挑选的正确性
如果条件换了,容量不再是2的倍数,而是和价钱一样,都是随意输入的,那么我目前也没有办法解决了,但是满足小容量是大容量的因子,这种方法都可以解决
#include<bits/stdc++.h>
typedef int64_t ll;
using namespace std;
ll n,l;
struct node
{
ll cnt,pow;
}kind[35];
int f(int a)
{
int ans=1;
while(a>1)
{
ans*=2;
a--;
}
return ans;
}
bool cmp(node a,node b)
{
if(a.pow/(a.cnt*1.0)>b.pow/(b.cnt*1.0))
return 1;
else
return 0;
}
ll bfs(ll left,ll cost,ll si)
{
ll i=left/kind[si].pow;//如果能装满,尽量装
cost+=i*kind[si].cnt;
left-=i*kind[si].pow;
if(left==0)//如果没有剩余容量了,递归停止,输出答案
return cost;
if(si==n)//如果后面没有其他种类的了,那么必须选当前种类的了,递归也要结束了
return cost+kind[si].cnt;
return min(cost+kind[si].cnt,bfs(left,cost,si+1));//判断一下是选当前种类值还是往后找值
}
int main()
{
scanf("%lld%lld",&n,&l);
for(int i=1;i<=n;i++)
{
scanf("%lld",&kind[i].cnt);
kind[i].pow=f(i); //计算容量
}
sort(kind+1,kind+n+1,cmp);//按照性价比排序
printf("%lld\n",bfs(l,0,1));
}