貪婪演算法(Greedy)

概念

在每一步採用當前看起來最好的選擇,進而希望使最終答案最好的方法

想想看

上圖的植物要如何吃到最多隻蟲? 從最近的蟲開始吃? 從一口氣能吃到最多蟲的地方開始吃?

雜談

Greedy可以說是在日常生活中,最常看見應用例子的演算法。

使用Greedy之前,要先想清楚每一步都採用當前看起來最好的選擇,真的能使最終答案最好嗎?

範例1 - 換錢

在銀行提款時,常常會拿到以最少紙鈔、硬幣組成的現金

要怎麼才能 n 元以最少的紙鈔、硬幣組成呢?

新台幣常用的紙鈔、硬幣有以下幾種:

  • 1元
  • 5元
  • 10元
  • 50元
  • 100元
  • 500元
  • 1000元

[input]

552
1246
10000

[output]

552=500*1 50*1 1*2
1246=1000*1 100*2 10*4 5*1 1*1
10000=1000*10

[想法]

用面額較大的紙鈔或硬幣,可以減少全部紙鈔和硬幣的數量

因此優先換面額較大的紙鈔或硬幣,換完才換較小的

[code]

#include<iostream>
using namespace std;

int main()
{
    int money[7];
    money[0] = 1000;
    money[1] = 500;
    money[2] = 100;
    money[3] = 50;
    money[4] = 10;
    money[5] = 5;
    money[6] = 1;

    int n, i;

    while( cin >> n )
    {
        cout << n << "=";
        for( i=0 ; i<=6 ; i++ )
        {
            if( n >= money[i] )
            {
                //       $1000       *        幾張
                cout << money[i] << "*" << n/money[i] << " ";
                n = n%money[i];
            }
        }
        cout << endl;
    }

    return 0;
}

自我思考

  • 如果新台幣加入一種新硬幣 23元 ,greedy法還會成立嗎?

範例2 - UVA Q12405 Scarecrow(稻草人)

點 ( . ) 表示良田,井號 ( # ) 表示不毛之地,一隻稻草人可以保護3格良田,下圖的要插3隻稻草人。

...##....##

[想法]

一開始沒放置稻草人時,所有地都沒被保護到

運算後,所有的好地一定要被稻草人保護到

由左往右看田地,一發現有好地沒被保護到,就放一個稻草人在此好地的右邊一格

該稻草人除了保護此地,還有機會保護到右邊一格右邊兩格的好地

[code]

#include<iostream>
using namespace std;

int main()
{
    int T;    //測資數量
    int N;    //農田的長度
    int ans;  //答案
    int Ti, i;
    char farmland[100];  //農田
    bool ok[100];   //農田有無被保護,true代表有受到保護

    while( cin >> T )//輸入測資數量
    {
        for(int Ti=1 ; Ti<=T ; Ti++ )
        {
            cin >> N >> farmland;

            //[initial][初始化]
            ans = 0;
            for( i=0 ; i<N ; i++ )
            {
                ok[i] = false;  //還沒放置稻草人,預設每個農田都會被烏鴉攻擊
            }

            //[greedy][貪婪演算法]
            for( i=0 ; i<N ; i++ )
            {
                if( farmland[i] == '.' and ok[i] == false ){  //'目前的地圖是可以耕耘的農田' and  '沒有受到稻草人保護'
                    //put a new scarecrow
                    ans++;          //放了一隻稻草人,稻草人數量+1
                    ok[i] = true;   //稻草人所在地的左方農田
                    ok[i+1] = true; //稻草人所在地的農田
                    ok[i+2] = true; //稻草人所在地的右方農田
                }
            }

            //[output]
            cout << "Case " << Ti << ": " << ans << endl;
        }
    }

    return 0;
}

延伸閱讀

results matching ""

    No results matching ""