http://poj.org/problem?id=3040
给奶牛发工资,每周至少 C 元。有面值V_i的硬币B_i个。
求最多能发几周?
贪心。分三个阶段:
(1)首先面额>=C的硬币直接发掉。
(2)对硬币面额从大到小尽量凑到接近C,且不超过C。
(3)按硬币面额从小到大尽量凑到接近C,允许大于C。
重复(2)(3)直到没有解。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int n,c;
int ans=0;
struct Node{
int val;
int num;
}a[30];
int use[30];
bool cmp(Node a,Node b){
return a.val<b.val;
}
int main(){
cin >> n >> c;
for (int i=0;i<n;i++){
scanf("%d %d",&a[i].val,&a[i].num);
}
sort(a,a+n,cmp);
for (int i=n-1;i>=0;i--){ // 步骤(1)
if (a[i].val>=c){
ans+=a[i].num;
a[i].num=0;
}
}
while (1){
int Min;
bool flag=false;
int sum=c;
memset(use,0,sizeof(use));
for (int i=n-1;i>=0;i--){ //步骤(2)
if (a[i].num>0){
use[i]=min(sum/a[i].val,a[i].num);
sum-=use[i]*a[i].val;
if (sum==0){
flag=1;
break;
}
}
}
if (sum>0){ //步骤(3)
for (int i=0;i<n;i++){
if(a[i].num-use[i]>0){
while (use[i]<a[i].num){
sum-=a[i].val;
use[i]++;
if (sum<=0){
flag=1;
break;
}
}
}
if (flag){
break;
}
}
}
if (!flag){
break;
}
Min=9999999;
for (int i=0;i<n;i++){
if (use[i]>0){
Min=min(Min,a[i].num/use[i]);
}
}
ans+=Min;
for (int i=0;i<n;i++){
if (use[i]>0){
a[i].num-=Min*use[i];
}
}
}
cout << ans << endl;
}