section 1.3 讲的是贪心算法(greedy algorithm),贪心算法虽然不一定普遍适用,但是对于某些问题,如果确定贪心算法对问题的解法是对的,那么使用贪心算法是非常有效的。本节的几个题目都需要使用贪心算法来求解。本文是本节的第一个问题 Mixing Milk
原文
Mixing Milk
Since milk packaging is such a low margin business, it is important to keep the price of the raw product (milk) as low as possible. Help Merry Milk Makers get the milk they need in the cheapest possible manner.
The Merry Milk Makers company has several farmers from which they may buy milk, and each one has a (potentially) different price at which they sell to the milk packing plant. Moreover, as a cow can only produce so much milk a day, the farmers only have so much milk to sell per day. Each day, Merry Milk Makers can purchase an integral amount of milk from each farmer, less than or equal to the farmer's limit.
Given the Merry Milk Makers' daily requirement of milk, along with the cost per gallon and amount of available milk for each farmer, calculate the minimum amount of money that it takes to fulfill the Merry Milk Makers' requirements.
Note: The total milk produced per day by the farmers will be sufficient to meet the demands of the Merry Milk Makers.
PROGRAM NAME: milk
INPUT FORMAT
Line 1: | Two integers, N and M. The first value, N, (0 <= N <= 2,000,000) is the amount of milk that Merry Milk Makers wants per day. The second, M, (0 <= M <= 5,000) is the number of farmers that they may buy from. |
Lines 2 through M+1: | The next M lines each contain two integers, Pi and Ai. Pi (0 <= Pi <= 1,000) is price in cents that farmer i charges. Ai (0 <= Ai <= 2,000,000) is the amount of milk that farmer i can sell to Merry Milk Makers per day. |
SAMPLE INPUT (file milk.in)
100 5 5 20 9 40 3 10 8 80 6 30
OUTPUT FORMAT
A single line with a single integer that is the minimum price that Merry Milk Makers can get their milk at for one day.
SAMPLE OUTPUT (file milk.out)
630
分析
提交代码
/*
ID:
PROG: milk
LANG: C++
*/
#include <fstream>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <map>
#include <iostream>
using namespace std;
int main()
{
int N,M;
ifstream ifile("milk.in");
ifile >> N >> M;
map<int,int> data;
for (int i=0;i!=M;i++)
{
int a,b;
ifile >> a >> b;
if(data.find(a) == data.end())
data[a] = b;
else
data[a] += b;
}
int cost=0;
int total=0;
for (map<int,int>::iterator itr = data.begin();itr != data.end();++itr)
{
if(total + itr->second <= N)
{
cost += itr->second * itr->first;
total += itr->second;
}
else
{
cost += itr->first * (N - total);
break;
}
}
ofstream fout("milk.out");
fout << cost << endl;
return 0;
}
提交结果
TASK: milk LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.000 secs, 3496 KB] Test 2: TEST OK [0.005 secs, 3496 KB] Test 3: TEST OK [0.005 secs, 3496 KB] Test 4: TEST OK [0.005 secs, 3496 KB] Test 5: TEST OK [0.008 secs, 3496 KB] Test 6: TEST OK [0.019 secs, 3496 KB] Test 7: TEST OK [0.011 secs, 3496 KB] Test 8: TEST OK [0.016 secs, 3496 KB] All tests OK.
官方给出的参考答案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAXFARMER 5000
typedef struct Farmer Farmer;
struct Farmer {
int p; /* price per gallon */
int a; /* amount to sell */
};
int
farmcmp(const void *va, const void *vb)
{
return ((Farmer*)va)->p - ((Farmer*)vb)->p;
}
int nfarmer;
Farmer farmer[MAXFARMER];
void
main(void)
{
FILE *fin, *fout;
int i, n, a, p;
fin = fopen("milk.in", "r");
fout = fopen("milk.out", "w");
assert(fin != NULL && fout != NULL);
fscanf(fin, "%d %d", &n, &nfarmer);
for(i=0; i<nfarmer; i++)
fscanf(fin, "%d %d", &farmer[i].p, &farmer[i].a);
qsort(farmer, nfarmer, sizeof(farmer[0]), farmcmp);
p = 0;
for(i=0; i<nfarmer && n > 0; i++) {
/* take as much as possible from farmer[i], up to amount n */
a = farmer[i].a;
if(a > n)
a = n;
p += a*farmer[i].p;
n -= a;
}
fprintf(fout, "%d\n", p);
exit(0);
}
这份答案里,使用了快速排序对输入数据进行了排序,复杂度为O(nlgn),官方下面给出的另一种方法则没有使用快速排序,而是直接建立一个大小为MAXPRICE的数组,数组按价格取下标,值即为相应价格的牛奶量。这个方法与本文使用map的方法类似,避免了排序的过程,复杂度为线性的,相比原先排序法降低了不少。
#include<stdio.h>
#define MAXPRICE 1001
int amount_for_price[MAXPRICE]={0};
int N, M;
int Cal(void);
int Read(void);
int main(void) {
Read();
Cal();
return 0;
}
int Cal(void) {
int i;
int price_total=0;
int milk_total=0;
for(i=0;i<MAXPRICE;i++) {
if(amount_for_price[i]) {
if(milk_total+amount_for_price[i]<N) {
price_total+=(i*amount_for_price[i]);
milk_total+=amount_for_price[i];
}
else {
int amount_needed = N-milk_total;
price_total+=(i*amount_needed);
break;
}
}
}
{
FILE* out=fopen("milk.out","w");
fprintf(out,"%d\n",price_total);
fclose(out);
}
return 0;
}
int Read(void) {
FILE* in = fopen("milk.in","r");
int i, price, amount;
fscanf(in,"%d %d",&N,&M);
for(i=0;i<M;i++) {
fscanf(in, "%d %d", &(price), &(amount));
amount_for_price[price]+=amount;
}
fclose(in);
return 0;
}