算法學習——貪心(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;
}

呼,終於把貪心的例題寫完了,明天繼續!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章