您的位置:首页 > 编程语言 > C语言/C++

USACO section1.3 Mixing Milk

2014-07-19 22:07 351 查看
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


分析

本题题意非常简单,从若干个奶农手里收购牛奶,直到达到需要的牛奶量,每个奶农能够的提供的牛奶量和单价都不同,求如何购买使得最终花费钱最少。
本题使用贪心算法的解决思路是,将提供牛奶的奶农按他们提供的单价排序,从单价最低的奶农手里收购牛奶,如果提供的牛奶不够满足需求量,则继续向单价第二低的奶农手里收购,如此依次收购直到满足需求的量。
由于涉及到对奶农按给出的单价排序,这里可以使用STL中的数据结构map,以奶农给出的单价作为map的第一个值,提供的牛奶量作为第二个值,由于map的特性,完成数据输入的同时,已经完成了按单价从小到大排序的过程。另外,由于可能有多个奶农以相同的单价提供,可以将以相同单价提供牛奶的奶农看成一个奶农,将他们提供的牛奶量累加起来。这样,我们只需要根据牛奶单价进行区分。

提交代码

/*
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;
}


THE END

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  USACO c++ 贪心算法