#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int M =25;
typedef pair<int ,int >Node; // 面值 和 数量
Node node[M];
int main()
{
int n,c,i,j,ans=0;
cin>>n>>c;
for(i=0;i<n;i++)
{
cin>>node[i].first>>node[i].second;
if(node[i].first>=c) //如果denomination大于c的 只能只接给咯
{
ans+=node[i].second;
node[i].second=0;
}
}
sort(node,node+n,greater<Node>() );
while(1)
{
int sum=c;
int need[M];// ~~!!!当前凑成 总额为sum的方案 need[i] i号coin需要多少个
memset(need,0,sizeof(need));
for(i=0;i<n;i++) //从大到小选出不大于sum的方案
{
if(sum&&node[i].second)
{
need[i]=min(node[i].second,sum/node[i].first); // 不大于 下取整
sum-= node[i].first*need[i];
}
}
int k;
// 用小的去凑出还差sum的那部分
for(i=n-1;i>=0;i--) //贪心 :如果凑出的和大于sum 则当前超出sum的部分应该尽量小->从小到大选
{
if(sum&&node[i].second)
{
k=min(node[i].second-need[i],(sum+node[i].first-1)/node[i].first); // 上取整
if(k!=0) // node[i]的数量 - need[i]可能为0 即不能在选
{
need[i]+=k;
sum-=need[i]*node[i].first;
}
}
}
if(sum>0) //怎么凑都凑不到sum
break;
//否则则找到一种方案
// 该方案可用次数等于 该方案所使用的 (子硬币i个数/(一次方案需要i的个数))中的最小值(因为一个方案中,所选硬币缺一不可)
int y=1<<30; // 若要组成15 10有100个 5有2个 1有1000个 则选10和5的方案只能用2次
for(i=0;i<n;i++)
{
if(need[i])
y=min(y,node[i].second/need[i]);
}
ans+=y;
for(i=0;i<n;i++)
{
if(need[i])
{
node[i].second-=y*need[i]; //更新使用
}
}
}
cout<<ans;
return 0;
}
poj 3040 Allowance贪心
最新推荐文章于 2023-07-09 16:03:37 发布