算法学习——贪心(2)

    贪心策略的题目思路还是挺简单的,重点是要考虑所有情况,只要多练习,还是可以AC的。最近刷题的速度有点下降,主要是还要复习线性代数和概率论等数学课和计算机网络等专业课,想想开学两周的课程设计真是神烦,加油~今天再练习几道~相信自己~


问题 D: Repair the Wall
时间限制: 1 Sec 内存限制: 32 MB

题目描述

Long time ago , Kitty lived in a small village. The air was fresh and the scenery was very beautiful. The only thing that troubled her is the typhoon.
When the typhoon came, everything is terrible. It kept blowing and raining for a long time. And what made the situation worse was that all of Kitty’s walls were made of wood.
One day, Kitty found that there was a crack in the wall. The shape of the crack is
a rectangle with the size of 1×L (in inch). Luckly Kitty got N blocks and a saw(锯子) from her neighbors.
The shape of the blocks were rectangle too, and the width of all blocks were 1 inch. So, with the help of saw, Kitty could cut down some of the blocks(of course she could use it directly without cutting) and put them in the crack, and the wall may be repaired perfectly, without any gap.
Now, Kitty knew the size of each blocks, and wanted to use as fewer as possible of the blocks to repair the wall, could you help her ?

输入
The problem contains many test cases, please process to the end of file( EOF ).
Each test case contains two lines.
In the first line, there are two integers L(0 < L < 1000000000) and N(0 <= N < 600) which
mentioned above.
In the second line, there are N positive integers. The ith integer Ai(0 < Ai < 1000000000 ) means that the ith block has the size of 1×Ai (in inch).

输出
For each test case , print an integer which represents the minimal number of blocks are needed.
If Kitty could not repair the wall, just print “impossible” instead.

样例输入
2 2
12 11
14 3
27 11 4
109 5
38 15 6 21 32
5 3
1 1 1

样例输出
1
1
5
impossible

解题思路
从大到小选择砖块尺寸来填补缝隙,如果当前砖块总尺寸大于缝隙尺寸,则朓出循环;如果遍历完所有砖块尺寸之和仍然小于缝隙尺寸,则输出”impossible”。

Submission

#include <stdio.h>
#include <algorithm>
using namespace std;
bool cmp(int a, int b) {
    return a > b;
}
int main() {
    int l_crack, n_block;
    while(scanf("%d%d", &l_crack, &n_block) != EOF) {
        int a[610] = {0};
        int sum_block = 0;
        int num_block = 0; 
        int flag_adequate = 0;
        for(int i = 0; i < n_block; i++) {
            scanf("%d", &a[i]);
        }
        sort(a, a + n_block, cmp);
        for(int i = 0; i <= n_block; i++) {
            if(sum_block  < l_crack) {
                sum_block += a[i];
                num_block ++;
            }
            else {
                flag_adequate = 1;
                break;
            }
        }
        if(flag_adequate == 1) {
            printf("%d\n", num_block);
        }
        else {
            printf("impossible\n");
        }
    }
    return 0;
}

问题 E: FatMouse’s Trade
时间限制: 1 Sec 内存限制: 32 MB

题目描述
FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean.
The warehouse has N rooms. The i-th room contains J[i] pounds of JavaBeans and requires F[i] pounds of cat food. FatMouse does not have to trade for all the JavaBeans in the room, instead, he may get J[i]* a% pounds of JavaBeans if he pays F[i]* a% pounds of cat food. Here a is a real number. Now he is assigning this homework to you: tell him the maximum amount of JavaBeans he can obtain.

输入
The input consists of multiple test cases. Each test case begins with a line containing two non-negative integers M and N. Then N lines follow, each contains two non-negative integers J[i] and F[i] respectively. The last test case is followed by two -1’s. All integers are not greater than 1000.

输出
For each test case, print in a single line a real number accurate up to 3 decimal places, which is the maximum amount of JavaBeans that FatMouse can obtain.

样例输入
4 2
4 7
1 3
5 5
4 8
3 8
1 2
2 5
2 4
-1 -1
样例输出
2.286
2.500

解题思路
按照 j / f 从大到小排序,优先选择更加划算的仓库进行交换,在从大到小遍历进行交易时,会出现两种情况:
(1)剩余的cat food可以对换第i个仓库的所有JavaBean;
(2)剩余的cat food只可对换第i个仓库a%的JavaBean
思路和D题一样,不过这儿涉及分数的计算,注意要把变量类型换为double即可。

Submission

#include <stdio.h>
#include <algorithm>
using namespace std;
typedef struct trade{
    double j;
    double f;
    double j_per_f;
}trade;
trade tra[1000];
bool cmp(trade a, trade b) {
    return a.j_per_f > b.j_per_f;
}
int main() {
    double m_pound;
    int n_room;
    while(scanf("%lf%d", &m_pound, &n_room), m_pound != -1, n_room != -1 ) {
        double j_per_f[1000] = {0}; 
        int rest_pound = 0;
        double max_javabean = 0; 
        int flag_adequate = 0;
        for(int i = 0; i < n_room; i++) {
            scanf("%lf%lf", &tra[i].j, &tra[i].f);
            tra[i].j_per_f = tra[i].j / tra[i].f;
        }
        sort(tra, tra + n_room, cmp);
        for(int i = 0; i <= n_room; i++) {
            if(m_pound >= tra[i].f) { //先选出能够整除的f[i]
                m_pound -= tra[i].f;
                max_javabean += tra[i].j;
            }
            else{
                max_javabean += tra[i].j_per_f * m_pound;//不能整除则按照j_per_f[i]交换
                m_pound = 0;
            }
            if(m_pound == 0) break;
        }
        printf("%.3f\n", max_javabean);
    }
    return 0;
}

问题 F: 迷瘴
时间限制: 1 Sec 内存限制: 32 MB

题目描述

小明正在玩游戏,他控制的角色正面临着幽谷的考验——
幽谷周围瘴气弥漫,静的可怕,隐约可见地上堆满了骷髅。由于此处长年不见天日,导致空气中布满了毒素,一旦吸入体内,便会全身溃烂而死。
幸好小明早有防备,提前备好了解药材料(各种浓度的万能药水)。现在只需按照配置成不同比例的浓度。
现已知小明随身携带有n种浓度的万能药水,体积V都相同,浓度则分别为Pi%。并且知道,针对当时幽谷的瘴气情况,只需选择部分或者全部的万能药水,然后配置出浓度不大于 W%的药水即可解毒。
现在的问题是:如何配置此药,能得到最大体积的当前可用的解药呢?
特别说明:由于幽谷内设备的限制,只允许把一种已有的药全部混入另一种之中(即:不能出现对一种药只取它的一部分这样的操作)。

输入

输入数据的第一行是一个整数C,表示测试数据的组数;
每组测试数据包含2行,首先一行给出三个正整数n,V,W(1<=n,V,W<=100);
接着一行是n个整数,表示n种药水的浓度Pi%(1<=Pi<=100)。

输出

对于每组测试数据,请输出一个整数和一个浮点数;
其中整数表示解药的最大体积,浮点数表示解药的浓度(四舍五入保留2位小数);
如果不能配出满足要求的的解药,则请输出0 0.00。

样例输入
2
1 35 68
1
2 79 25
59 63
样例输出
35 0.01
0 0.00

解题思路
题目要求可以简化为:用n瓶浓度为Pi [ i ] 、体积为V的解药调配最大体积的浓度不大于W的解药。解题思路为将解药浓度从小到大排序,每次加入的解药浓度尽可能小,超前计算下一瓶解药加入后的浓度,浓度大于W时朓出循环。

Submission

#include <stdio.h>
#include <algorithm>
using namespace std;
int main() {
    int c;
    scanf("%d", &c);
    while(c--) {
        int i, n, V;
        int Pi[101];
        double W;
        int curV = 0;
        double curPi = 0;
        scanf("%d%d%lf",&n, &V, &W);
        for(i = 0; i < n; i++) {
            scanf("%d", &Pi[i]);
        }
        sort(Pi, Pi + n);
        for(i = 0; i < n; i++) {
            if((curPi + Pi[i]) / (i + 1) > W) {
                break;
            } 
            curPi += Pi[i];
        }
        if(curPi > 0) printf("%d %.2f\n", V * i, curPi / (i * 100));
        else printf("0 0.00\n");
    }
    return 0;
}

问题 G: 找零钱
时间限制: 1 Sec 内存限制: 128 MB

题目描述
小智去超市买东西,买了不超过一百块的东西。收银员想尽量用少的纸币来找钱。
纸币面额分为50 20 10 5 1 五种。请在知道要找多少钱n给小明的情况下,输出纸币数量最少的方案。 1<=n<=99;
输入
有多组数据 1<=n<=99;
输出
对于每种数量不为0的纸币,输出他们的面值*数量,再加起来输出
样例输入
25
32
样例输出
20*1+5*1
20*1+10*1+1*2

解题思路
因为要尽可能用少数量的纸币找零,因此从大的纸币开始计算。

Submission

#include <stdio.h>
int main() {
    int n;
    while(scanf("%d", &n) != EOF){
        int paper[5] = {50, 20, 10, 5, 1};
        int num[5] = {0};
        int i, j;
        for(i = 0; i < 5; i++){
            if(n > 0 && n >= paper[i]) {
                num[i] = n / paper[i];
                n -= paper[i] * num[i];
            }
            if(n == 0) break;
        }
        for(j = 0; j < i + 1; j++) {
            if(num[j] != 0) {
                if(j != i) printf("%d*%d+", paper[j], num[j]);
                else printf("%d*%d\n", paper[j], num[j]);
            }
        }
    }
    return 0;
}

呼,终于把贪心的例题写完了,明天继续!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值