【原创】【合并类贪心】POJ 3253 1862 2709; Fence Repair && Stripies && Painter

来源:互联网 发布:linux 挂载iso 编辑:程序博客网 时间:2024/06/01 08:47

合并类贪心

基础题和原理解释

首先这里有个合并类的基础题目,合并果子(分卷子)。(不是合并石子),本次的主角就是它(还有优先队列),而这道题目和代码就丢在:这个链接里了,还有一道87%一模一样的题叫做分卷子,也可以这么做。

但是,原理是什么呢?

合并的过程我们可以看做一颗二叉树。
这里写图片描述
就合并果子而言,一开始的N堆果子有大有小。而我们希望每次花的体力尽可能少。如果我们先合并比较大的一堆和某堆(合并的结果记为堆A),而不是比较小的一堆和某堆合并。那么首先,我们这一次就会多花体力。其次,我们之后合并的时候,必定会合并到堆A,我们那么比较大的这堆就会比较小的一堆多被合并一次,体力自然会花的多。因此,我们希望合并的时候,尽可能的合并较小的两堆,那么,我们可以用优先队列维护果子,每次取出最小的两个,合并,重新放进去。

同类题目汇总

接着我们来看几道同类题目。

POJ 3253 Fence Repair

Farmer John wants to repair a small length of the fence around the pasture. He measures the fence and finds that he needs N (1 ≤ N ≤ 20,000) planks of wood, each having some integer length Li (1 ≤ Li ≤ 50,000) units. He then purchases a single long board just long enough to saw into the N planks (i.e., whose length is the sum of the lengths Li). FJ is ignoring the “kerf”, the extra length lost to sawdust when a sawcut is made; you should ignore it, too.

FJ sadly realizes that he doesn’t own a saw with which to cut the wood, so he mosies over to Farmer Don’s Farm with this long board and politely asks if he may borrow a saw.

Farmer Don, a closet capitalist, doesn’t lend FJ a saw but instead offers to charge Farmer John for each of the N-1 cuts in the plank. The charge to cut a piece of wood is exactly equal to its length. Cutting a plank of length 21 costs 21 cents.

Farmer Don then lets Farmer John decide the order and locations to cut the plank. Help Farmer John determine the minimum amount of money he can spend to create the N planks. FJ knows that he can cut the board in various different orders which will result in different charges since the resulting intermediate planks are of different lengths.

Input
Line 1: One integer N, the number of planks
Lines 2.. N+1: Each line contains a single integer describing the length of a needed plank
Output
Line 1: One integer: the minimum amount of money he must spend to make N-1 cuts
Sample Input
3
8
5
8
Sample Output
34
Hint
He wants to cut a board of length 21 into pieces of lengths 8, 5, and 8.
The original board measures 8+5+8=21. The first cut will cost 21, and should be used to cut the board into pieces measuring 13 and 8. The second cut will cost 13, and should be used to cut the 13 into 8 and 5. This would cost 21+13=34. If the 21 was cut into 16 and 5 instead, the second cut would cost 16 for a total of 37 (which is more than 34).

题意

要把一块木板锯成N块木板,每块木板的长度给定。每砍一刀要花钱,费用为你锯的木板的长度。

分析

这道题目你可以把它理解为逆向的合并果子。你从一个顶点开始,把它一分为二,就像上面的图一样,直到最后是题目给出的那些木板。
从上往下和从下往上的费用是完全等价的,可以直接Copy借用合并果子的代码啦!

代码

#include<iostream>#include<queue>#include<algorithm>using namespace std;#define sc(a) cin>>npriority_queue<long long,vector<long long>,greater<long long> > climax;long long n,d,a,b,ans;int main(){    while(cin>>n)    {        ans=0;        while(!climax.empty()) climax.pop();        for(long long i=1;i<=n;i++)            cin>>d,climax.push(d);        for(long long i=1;i<n;i++)        {            a=climax.top(); climax.pop();            b=climax.top(); climax.pop();            ans+=a+b; climax.push(a+b);        }        cout<<ans<<endl;    }}

POJ 1862 Stripies

Our chemical biologists have invented a new very useful form of life called stripies (in fact, they were first called in Russian - polosatiki, but the scientists had to invent an English name to apply for an international patent). The stripies are transparent amorphous amebiform creatures that live in flat colonies in a jelly-like nutrient medium. Most of the time the stripies are moving. When two of them collide a new stripie appears instead of them. Long observations made by our scientists enabled them to establish that the weight of the new stripie isn’t equal to the sum of weights of two disappeared stripies that collided; nevertheless, they soon learned that when two stripies of weights m1 and m2 collide the weight of resulting stripie equals to 2*sqrt(m1*m2). Our chemical biologists are very anxious to know to what limits can decrease the total weight of a given colony of stripies.
You are to write a program that will help them to answer this question. You may assume that 3 or more stipies never collide together.
Input
The first line of the input contains one integer N (1 <= N <= 100) - the number of stripies in a colony. Each of next N lines contains one integer ranging from 1 to 10000 - the weight of the corresponding stripie.
Output
The output must contain one line with the minimal possible total weight of colony with the accuracy of three decimal digits after the point.
Sample Input
3
72
30
50
Sample Output
120.000

题意

有n只神奇的变形小虫虫,每只小虫虫都有质量mi。两只小虫虫(mp和mq)可以合二为一,新的小虫虫的质量是2*sqrt(mp*mq)。最后合并成一只小虫虫,求这只小虫虫最小的质量。

分析

这也是一道合并类贪心。我们希望质量最小,那么质量大的小虫虫应该多开方几次,最后的结果就小了。所以只需维护一个降序的优先队列即可。

代码

#include<cstdio>#include<cmath>#include<cstring>#include<iostream>#include<queue>#include<algorithm>using namespace std;priority_queue<double,vector<double>,less<double> > climax;double n,d,a,b,ans;int main(){    while(cin>>n)    {        while(!climax.empty()) climax.pop();        for(int i=1;i<=n;i++)            cin>>d,climax.push(d);        for(int i=1;i<n;i++)        {            a=climax.top(); climax.pop();            b=climax.top(); climax.pop();            climax.push(2*sqrt(a*b));        }        printf("%.3lf\n",climax.top());    }}

POJ 2709 Painter

The local toy store sells small fingerpainting kits with between three and twelve 50ml bottles of paint, each a different color. The paints are bright and fun to work with, and have the useful property that if you mix X ml each of any three different colors, you get X ml of gray. (The paints are thick and “airy”, almost like cake frosting, and when you mix them together the volume doesn’t increase, the paint just gets more dense.) None of the individual colors are gray; the only way to get gray is by mixing exactly three distinct colors, but it doesn’t matter which three. Your friend Emily is an elementary school teacher and every Friday she does a fingerpainting project with her class. Given the number of different colors needed, the amount of each color, and the amount of gray, your job is to calculate the number of kits needed for her class.
Input
The input consists of one or more test cases, followed by a line containing only zero that signals the end of the input. Each test case consists of a single line of five or more integers, which are separated by a space. The first integer N is the number of different colors (3 <= N <= 12). Following that are N different nonnegative integers, each at most 1,000, that specify the amount of each color needed. Last is a nonnegative integer G <= 1,000 that specifies the amount of gray needed. All quantities are in ml.
Output
For each test case, output the smallest number of fingerpainting kits sufficient to provide the required amounts of all the colors and gray. Note that all grays are considered equal, so in order to find the minimum number of kits for a test case you may need to make grays using different combinations of three distinct colors.
Sample Input
3 40 95 21 0
7 25 60 400 250 0 60 0 500
4 90 95 75 95 10
4 90 95 75 95 11
5 0 0 0 0 0 333
0
Sample Output
2
8
2
3
4

题意

你需要各种颜色的颜料,给定对各个颜色的需求量。
商店出售各种颜色除了灰色的颜料,以套装出售。一套包含所有除了灰色的颜色各50ml,而灰色颜料可以由其他任意三种互异的颜料合成,各xml的三种颜料可以合成xml的灰色。比如300ml的红,300ml的绿,300ml的紫,可以合成300ml的灰色。
问最少买几套。

分析

首先满足普通颜色的需求。买的套装能满足其中最大的需求量即可,比如说66,99,买两套就可以了。
既然满足了最多的颜色,那么其他较少的颜色就会有剩余。我们可以用剩余的颜料来合成。
此时怎么合成呢?
分类讨论:

  1. 剩余颜料不足3种:无法继续合成灰色了,需要再买一个套装。
  2. 剩余颜料比3种多:我们可以合成灰色。

拿哪些颜料来合成呢?
既然我们想要尽可能少的买套装,我们就要尽可能充分的利用所有的颜料。也就是说,尽可能地拖时间,让每个套装都尽可能的发挥功效,让情况1尽可能少出现。不要盲目的乱花。
比如6 6 6 3 3,如果把前面3个合成了,那么就0 0 0 3 3,合成六套,再买套装。但是我节省一点,我可以把所有颜料都花完,合成八套。

经过上述这么多废话,我们不难想出解决办法:
维护一个降序的优先队列,取前三个元素,每次合成1ml灰色颜料。这就避免了上述情况的发生。
(代码用的是数组,方便买套装的时候更新元素,但本质相同)

代码

#include<cstdio>#include<algorithm>#include<queue>using namespace std;bool Read(int &p){    p=0;    char c=getchar();    while(c<'0'||c>'9') c=getchar();    while(c>='0'&&c<='9')        p=p*10+c-'0',c=getchar();    return 1;}int n,A[15],res[15],G,mx,ans,a,b,c;bool cmp(int a,int b){    return a>b;}int main(){    while(Read(n)&&n)    {        mx=-1;        for(int i=1;i<=n;i++) Read(A[i]),mx=max(mx,A[i]);        Read(G);        ans=mx/50+(mx%50!=0);        for(int i=1;i<=n;i++)            res[i]=(50*ans-A[i]);        while(G>0)        {            sort(res+1,res+1+n,cmp);            a=res[1]; b=res[2]; c=res[3];            if(c==0)             {                for(int i=1;i<=n;i++)                    res[i]+=50;                ans++;            }            else res[1]--,res[2]--,res[3]--,G--;        }        printf("%d\n",ans);    }}
原创粉丝点击