貪心演算法2

2021-04-23 00:00:47 字數 2847 閱讀 7920

在求最優解問題的過程中,依據某種貪心標準,從問題的初始狀態出發,直接去求解每一步的最優解,通過若干次的貪心選擇,最終得出整個問題的最優解,這種求解方法就是談心演算法。

從貪心演算法的定義可以看出,貪心法並不是從整體上考慮問題,它所做出的選擇只是在某中意義上的區域性最優解,而由問題自身的特性決定了該題運用貪心演算法可以得到最優解。

例題1:均分紙牌(noip2002tg)

問題描述:有n堆紙牌,編號分別為1,2,…,n。每堆上有若干張,但紙牌總數必為n的倍數.可以在任一堆上取若干張紙牌,然後移動。移牌的規則為:在編號為1上取的紙牌,只能移到編號為2的堆上;在編號為n的堆上取的紙牌,只能移到編號為n-1的堆上;其他堆上取的紙牌,可以移到相鄰左邊或右邊的堆上。現在要求找出一種移動方法,用最少的移動次數使每堆上紙牌數都一樣多。例如:n=4,4堆紙牌分別為:① 9 ② 8 ③ 17 ④ 6 移動三次可以達到目的:從③取4張牌放到④ 再從③區3張放到②然後從②去1張放到①。

輸入:鍵盤輸入檔名。

檔案格式:n (n堆紙牌 1<=n<=100)

a1,a2,a3,… an(n堆紙牌,每堆紙牌初始數,1<=ai<=10000)

輸出:輸出至螢幕。格式為:所有堆數均達到相等時的最少移動次數。

輸入輸出樣例:a.in:4 9

8176

螢幕顯示:3

演算法分析:設a[i]為第i堆紙牌的張數(0<=i<=n),v為均分後每堆紙牌的張數,s為最小移動次數。

我們用貪心法,按照從左到右的順序移動紙牌。如第i堆的紙牌數不等於平均值,則移動一次(即s加1),分兩種情況移動:

1.若a[i]>v,則將a[i]-v張從第i堆移動到第i+1堆;

2.若a[i]

為了設計的方便,我們把這兩種情況統一看作是將a[i]-v從第i堆移動到第i+1堆,移動後有a[i]=v;a[i+1]=a[i+1]+a[i]-v.

在從第i+1堆取出紙牌補充第i堆的過程中可能回出現第i+1堆的紙牌小於零的情況。

如n=3,三堆指派數為1227 ,這時v=10,為了使第一堆為10,要從第二堆移9張到第一堆,而第二堆只有2張可以移,這是不是意味著剛才使用貪心法是錯誤的呢?

我們繼續按規則分析移牌過程,從第二堆移出9張到第一堆後,第一堆有10張,第二堆剩下-7張,在從第三堆移動17張到第二堆,剛好三堆紙牌都是10,最後結果是對的,我們在移動過程中,只是改變了移動的順序,而移動次數不便,因此此題使用貪心法可行的。

源程式:

vari,n,s:integer;v:longint;a:array[1..100] of longint;

f:text;fil:string;

beginrealn(fil);

assign(f,fi);reset(f);

readln(f,n); v:=0;

for i:=1 to n do begin

read(f,a[i]), inc(v,a[i]);

end;

v:=v div n;

for i:=1 to n-1 do

if a[i]<>v then

begininc(s);

a[i+1]=a[i+1]+a[i]-v;

end;

writeln(s);

end.

利用貪心法解題,需要解決兩個問題:

一是問題是否適合用貪心法求解。我們看乙個找幣的例子,如果乙個貨幣系統有三種幣值,面值分別為一角、五分和一分,求最小找幣數時,可以用貪心法求解;如果將這三種幣值改為一角一分、五分和一分,就不能使用貪心法求解。用貪心法解題很方便,但它的適用範圍很小,判斷乙個問題是否適合用貪心法求解,目前還沒有乙個通用的方法,在資訊學競賽中,需要憑個人的經驗來判斷何時該使用貪心演算法。

二是確定了可以用貪心演算法之後,如何選擇乙個貪心標準,才能保證得到問題的最優解。在選擇貪心標準時,我們要對所選的貪心標準進行驗證才能使用,不要被表面上看似正確的貪心標準所迷惑,如下面的例子。

例題2:設有n個正整數,將它們連線成一排,組成乙個最大的多位整數。

例如:n=3時,3個整數13,312,343,連成的最大整數為34331213。

又如:n=4時,4個整數7,13,4,246,連成的最大整數為7424613。

輸入:n

n個數輸出:連成的多位數

演算法分析:此題很容易想到使用貪心法,在考試時有很多同學把整數按從大到小的順序連線起來,測試題目的例子也都符合,但最後測試的結果卻不全對。按這種標準,我們很容易找到反例:12,121應該組成12121而非12112,那麼是不是相互包含的時候就從小到大呢?也不一定,如12,123就是12312而非12123,這種情況就有很多種了。是不是此題不能用貪心法呢?

其實此題可以用貪心法來求解,只是剛才的標準不對,正確的標準是:先把整數轉換成字串,然後在比較a+b和b+a,如果a+b>b+a,就把a排在b的前面,反之則把a排在b的後面。

源程式:

vars:array[1..20] of string;

t:string;i,k,j,n:longint;

begin

readln(n);

for i:=1 to n do

beginread(k);

str(k,s[i]);

end;

fori:=1 to n-1 do

for j:=i+1 to n do

if s[i]+s[j]then

begint:=s[i];

s[i]:=s[j];

s[j]:=t;

end;

for i:=1 to n dowrite(s[i]);

end.

貪心演算法所作的選擇可以依賴於以往所作過的選擇,但決不依賴於將來的選擇,也不依賴於子問題的解,因此貪心演算法與其他演算法相比具有一定的速度優勢。如果乙個問題可以同時用幾種方法解決,談心演算法應該是最好的選擇之一。

貪心演算法(2)

題目描述 通過懸崖的yifenfei,又面臨著幽谷的考驗 幽谷周圍瘴氣瀰漫,靜的可怕,隱約可見地上堆滿了骷髏。由於此處長年不見天日,導致空氣中布滿了毒素,一旦吸入體內,便會全身潰爛而死。幸好yifenfei早有防備,提前備好了解藥材料 各種濃度的萬能藥水 現在只需按照配置成不同比例的濃度。現已知yi...

貪心演算法2

太難的題沒有做出來,所以就寫兩道印象較為深刻的題。1.最小新整數 給定乙個十進位制正整數n 0 n 1000000000 每個數字上數字均不為0。n的位數為m。現在從m位中刪除k位 0 include using namespace std char a 1000000000 intmain if ...

貪心演算法2

多處最優服務次序問題。問題描述 設有n個顧客同時等待一項服務,顧客i需要的服務時間為ti,1 i n 共有s處可以提供此項服務。應如何安排n個顧客的服務次序才能使平均等待時間達到最小?輸入 第一行為兩個正整數n和s 第二行為n個正整數,表示n個顧客需要的服務時間 輸出 最小平均等待時間。includ...