www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > C語(yǔ)言與CPP編程
[導(dǎo)讀]貪心算法是指在對(duì)問(wèn)題求解時(shí),總是做出在當(dāng)前看來(lái)是最好的選擇。也就是說(shuō),不從整體最優(yōu)上加以考慮,只做出在某種意義上的局部最優(yōu)解。貪心算法不是對(duì)所有問(wèn)題都能得到整體最優(yōu)解,關(guān)鍵是貪心策略的選擇,選擇的貪心策略必須具備無(wú)后效性,即某個(gè)狀態(tài)以前的過(guò)程不會(huì)影響以后的狀態(tài),只與當(dāng)前狀態(tài)有關(guān)。

來(lái)源:大魚(yú)機(jī)器人


01

基本概念


貪心算法是指在對(duì)問(wèn)題求解時(shí),總是做出在當(dāng)前看來(lái)是最好的選擇。也就是說(shuō),不從整體最優(yōu)上加以考慮,只做出在某種意義上的局部最優(yōu)解。貪心算法不是對(duì)所有問(wèn)題都能得到整體最優(yōu)解,關(guān)鍵是貪心策略的選擇,選擇的貪心策略必須具備無(wú)后效性,即某個(gè)狀態(tài)以前的過(guò)程不會(huì)影響以后的狀態(tài),只與當(dāng)前狀態(tài)有關(guān)。


貪心算法沒(méi)有固定的算法框架,算法設(shè)計(jì)的關(guān)鍵是貪心策略的選擇。必須注意的是,貪心算法不是對(duì)所有問(wèn)題都能得到整體最優(yōu)解,選擇的貪心策略必須具備無(wú)后效性(即某個(gè)狀態(tài)以后的過(guò)程不會(huì)影響以前的狀態(tài),只與當(dāng)前狀態(tài)有關(guān)。)


所以,對(duì)所采用的貪心策略一定要仔細(xì)分析其是否滿(mǎn)足無(wú)后效性。


02

貪心算法的基本思路


解題的一般步驟是:


1.建立數(shù)學(xué)模型來(lái)描述問(wèn)題;
2.把求解的問(wèn)題分成若干個(gè)子問(wèn)題;
3.對(duì)每一子問(wèn)題求解,得到子問(wèn)題的局部最優(yōu)解;
4.把子問(wèn)題的局部最優(yōu)解合成原來(lái)問(wèn)題的一個(gè)解。


03

該算法存在的問(wèn)題


  • 不能保證求得的最后解是最佳的

  • 不能用來(lái)求最大值或最小值的問(wèn)題

  • 只能求滿(mǎn)足某些約束條件的可行解的范圍


04

貪心算法適用的問(wèn)題


貪心策略適用的前提是:局部最優(yōu)策略能導(dǎo)致產(chǎn)生全局最優(yōu)解。


實(shí)際上,貪心算法適用的情況很少。一般對(duì)一個(gè)問(wèn)題分析是否適用于貪心算法,可以先選擇該問(wèn)題下的幾個(gè)實(shí)際數(shù)據(jù)進(jìn)行分析,就可以做出判斷。


05

貪心選擇性質(zhì)


所謂貪心選擇性質(zhì)是指所求問(wèn)題的整體最優(yōu)解可以通過(guò)一系列局部最優(yōu)的選擇,換句話(huà)說(shuō),當(dāng)考慮做何種選擇的時(shí)候,我們只考慮對(duì)當(dāng)前問(wèn)題最佳的選擇而不考慮子問(wèn)題的結(jié)果。這是貪心算法可行的第一個(gè)基本要素。貪心算法以迭代的方式作出相繼的貪心選擇,每作一次貪心選擇就將所求問(wèn)題簡(jiǎn)化為規(guī)模更小的子問(wèn)題。對(duì)于一個(gè)具體問(wèn)題,要確定它是否具有貪心選擇性質(zhì),必須證明每一步所作的貪心選擇最終導(dǎo)致問(wèn)題的整體最優(yōu)解。


當(dāng)一個(gè)問(wèn)題的最優(yōu)解包含其子問(wèn)題的最優(yōu)解時(shí),稱(chēng)此問(wèn)題具有最優(yōu)子結(jié)構(gòu)性質(zhì)。問(wèn)題的最優(yōu)子結(jié)構(gòu)性質(zhì)是該問(wèn)題可用貪心算法求解的關(guān)鍵特征。


06

貪心算法的實(shí)現(xiàn)框架


從問(wèn)題的某一初始解出發(fā):


while (朝給定總目標(biāo)前進(jìn)一步){ 利用可行的決策,求出可行解的一個(gè)解元素。}


由所有解元素組合成問(wèn)題的一個(gè)可行解;


07

例題分析


如果大家比較了解動(dòng)態(tài)規(guī)劃,就會(huì)發(fā)現(xiàn)它們之間的相似之處。最優(yōu)解問(wèn)題大部分都可以拆分成一個(gè)個(gè)的子問(wèn)題,把解空間的遍歷視作對(duì)子問(wèn)題樹(shù)的遍歷,則以某種形式對(duì)樹(shù)整個(gè)的遍歷一遍就可以求出最優(yōu)解,大部分情況下這是不可行的。貪心算法和動(dòng)態(tài)規(guī)劃本質(zhì)上是對(duì)子問(wèn)題樹(shù)的一種修剪,兩種算法要求問(wèn)題都具有的一個(gè)性質(zhì)就是子問(wèn)題最優(yōu)性(組成最優(yōu)解的每一個(gè)子問(wèn)題的解,對(duì)于這個(gè)子問(wèn)題本身肯定也是最優(yōu)的)。動(dòng)態(tài)規(guī)劃方法代表了這一類(lèi)問(wèn)題的一般解法,我們自底向上構(gòu)造子問(wèn)題的解,對(duì)每一個(gè)子樹(shù)的根,求出下面每一個(gè)葉子的值,并且以其中的最優(yōu)值作為自身的值,其它的值舍棄。而貪心算法是動(dòng)態(tài)規(guī)劃方法的一個(gè)特例,可以證明每一個(gè)子樹(shù)的根的值不取決于下面葉子的值,而只取決于當(dāng)前問(wèn)題的狀況。換句話(huà)說(shuō),不需要知道一個(gè)節(jié)點(diǎn)所有子樹(shù)的情況,就可以求出這個(gè)節(jié)點(diǎn)的值。由于貪心算法的這個(gè)特性,它對(duì)解空間樹(shù)的遍歷不需要自底向上,而只需要自根開(kāi)始,選擇最優(yōu)的路,一直走到底就可以了。

話(huà)不多說(shuō),我們來(lái)看幾個(gè)具體的例子慢慢理解它:

1.活動(dòng)選擇問(wèn)題

這是《算法導(dǎo)論》上的例子,也是一個(gè)非常經(jīng)典的問(wèn)題。有n個(gè)需要在同一天使用同一個(gè)教室的活動(dòng)a1,a2,…,an,教室同一時(shí)刻只能由一個(gè)活動(dòng)使用。每個(gè)活動(dòng)ai都有一個(gè)開(kāi)始時(shí)間si和結(jié)束時(shí)間fi 。一旦被選擇后,活動(dòng)ai就占據(jù)半開(kāi)時(shí)間區(qū)間[si,fi)。如果[si,fi]和[sj,fj]互不重疊,ai和aj兩個(gè)活動(dòng)就可以被安排在這一天。該問(wèn)題就是要安排這些活動(dòng)使得盡量多的活動(dòng)能不沖突的舉行。例如下圖所示的活動(dòng)集合S,其中各項(xiàng)活動(dòng)按照結(jié)束時(shí)間單調(diào)遞增排序。



考慮使用貪心算法的解法。為了方便,我們用不同顏色的線(xiàn)條代表每個(gè)活動(dòng),線(xiàn)條的長(zhǎng)度就是活動(dòng)所占據(jù)的時(shí)間段,藍(lán)色的線(xiàn)條表示我們已經(jīng)選擇的活動(dòng);紅色的線(xiàn)條表示我們沒(méi)有選擇的活動(dòng)。

如果我們每次都選擇開(kāi)始時(shí)間最早的活動(dòng),不能得到最優(yōu)解:



如果我們每次都選擇持續(xù)時(shí)間最短的活動(dòng),不能得到最優(yōu)解:



可以用數(shù)學(xué)歸納法證明,我們的貪心策略應(yīng)該是每次選取結(jié)束時(shí)間最早的活動(dòng)。直觀(guān)上也很好理解,按這種方法選擇相容活動(dòng)為未安排活動(dòng)留下盡可能多的時(shí)間。這也是把各項(xiàng)活動(dòng)按照結(jié)束時(shí)間單調(diào)遞增排序的原因。

#include#include#includeusing namespace std; int N;struct Act{ int start; int end;}act[100010];
bool cmp(Act a,Act b) { return a.end}
int greedy_activity_selector() { int num=1,i=1; for(int j=2;j<=N;j++) { if(act[j].start>=act[i].end) { i=j; num++; } } return num;}
int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&N); for(int i=1;i<=N;i++) { scanf("%lld %lld",&act[i].start,&act[i].end); } act[0].start=-1; act[0].end=-1; sort(act+1,act+N+1,cmp); int res=greedy_activity_selector(); cout<endl; }}

2.錢(qián)幣找零問(wèn)題


這個(gè)問(wèn)題在我們的日常生活中就更加普遍了。假設(shè)1元、2元、5元、10元、20元、50元、100元的紙幣分別有c0, c1, c2, c3, c4, c5, c6張?,F(xiàn)在要用這些錢(qián)來(lái)支付K元,至少要用多少?gòu)埣垘??用貪心算法的思想,很顯然,每一步盡可能用面值大的紙幣即可。在日常生活中我們自然而然也是這么做的。在程序中已經(jīng)事先將Value按照從小到大的順序排好。

#include#includeusing namespace std;const int N=7;int Count[N]={3,0,2,1,0,3,5};int Value[N]={1,2,5,10,20,50,100};
int solve(int money){ int num=0; for(int i=N-1;i>=0;i--) { int c=min(money/Value[i],Count[i]); money=money-c*Value[i]; num+=c; } if(money>0) num=-1; return num;}
int main(){ int money; cin>>money; int res=solve(money); if(res!=-1) cout<endl; else cout<<"NO"<<endl;}

3.再論背包問(wèn)題


在從零開(kāi)始學(xué)動(dòng)態(tài)規(guī)劃中我們已經(jīng)談過(guò)三種最基本的背包問(wèn)題:零一背包,部分背包,完全背包。很容易證明,背包問(wèn)題不能使用貪心算法。然而我們考慮這樣一種背包問(wèn)題:在選擇物品i裝入背包時(shí),可以選擇物品的一部分,而不一定要全部裝入背包。這時(shí)便可以使用貪心算法求解了。計(jì)算每種物品的單位重量?jī)r(jià)值作為貪心選擇的依據(jù)指標(biāo),選擇單位重量?jī)r(jià)值最高的物品,將盡可能多的該物品裝入背包,依此策略一直地進(jìn)行下去,直到背包裝滿(mǎn)為止。在零一背包問(wèn)題中貪心選擇之所以不能得到最優(yōu)解原因是貪心選擇無(wú)法保證最終能將背包裝滿(mǎn),部分閑置的背包空間使每公斤背包空間的價(jià)值降低了。在程序中已經(jīng)事先將單位重量?jī)r(jià)值按照從大到小的順序排好。

#include using namespace std; const int N=4; void knapsack(float M,float v[],float w[],float x[]); 
int main() { float M=50; //背包所能容納的重量 float w[]={0,10,30,20,5}; //每種物品的重量 float v[]={0,200,400,100,10}; //每種物品的價(jià)值 float x[N+1]={0}; //記錄結(jié)果的數(shù)組 knapsack(M,v,w,x); cout<<"選擇裝下的物品比例:"<<endl; for(int i=1;i<=N;i++) cout<<"["<"]:"<endl; }
void knapsack(float M,float v[],float w[],float x[]) { int i; //物品整件被裝下 for(i=1;i<=N;i++) { if(w[i]>M) break; x[i]=1; M-=w[i]; } //物品部分被裝下 if(i<=N) x[i]=M/w[i]; }

4.多機(jī)調(diào)度問(wèn)題


n個(gè)作業(yè)組成的作業(yè)集,可由m臺(tái)相同機(jī)器加工處理。要求給出一種作業(yè)調(diào)度方案,使所給的n個(gè)作業(yè)在盡可能短的時(shí)間內(nèi)由m臺(tái)機(jī)器加工處理完成。作業(yè)不能拆分成更小的子作業(yè);每個(gè)作業(yè)均可在任何一臺(tái)機(jī)器上加工處理。這個(gè)問(wèn)題是NP完全問(wèn)題,還沒(méi)有有效的解法(求最優(yōu)解),但是可以用貪心選擇策略設(shè)計(jì)出較好的近似算法(求次優(yōu)解)。當(dāng)n<=m時(shí),只要將作業(yè)時(shí)間區(qū)間分配給作業(yè)即可;當(dāng)n>m時(shí),首先將n個(gè)作業(yè)從大到小排序,然后依此順序?qū)⒆鳂I(yè)分配給空閑的處理機(jī)。也就是說(shuō)從剩下的作業(yè)中,選擇需要處理時(shí)間最長(zhǎng)的,然后依次選擇處理時(shí)間次長(zhǎng)的,直到所有的作業(yè)全部處理完畢,或者機(jī)器不能再處理其他作業(yè)為止。如果我們每次是將需要處理時(shí)間最短的作業(yè)分配給空閑的機(jī)器,那么可能就會(huì)出現(xiàn)其它所有作業(yè)都處理完了只剩所需時(shí)間最長(zhǎng)的作業(yè)在處理的情況,這樣勢(shì)必效率較低。在下面的代碼中沒(méi)有討論n和m的大小關(guān)系,把這兩種情況合二為一了。

#include #include using namespace std; int speed[10010]; int mintime[110]; 
bool cmp( const int &x,const int &y) { return x>y; }
int main() { int n,m; memset(speed,0,sizeof(speed)); memset(mintime,0,sizeof(mintime)); cin>>n>>m; for(int i=0;icin>>speed[i]; sort(speed,speed+n,cmp); for(int i=0;i { *min_element(mintime,mintime+m)+=speed[i]; } cout<<*max_element(mintime,mintime+m)<<endl;}


5.小船過(guò)河問(wèn)題


POJ1700是一道經(jīng)典的貪心算法例題。題目大意是只有一艘船,能乘2人,船的運(yùn)行速度為2人中較慢一人的速度,過(guò)去后還需一個(gè)人把船劃回來(lái),問(wèn)把n個(gè)人運(yùn)到對(duì)岸,最少需要多久。先將所有人過(guò)河所需的時(shí)間按照升序排序,我們考慮把單獨(dú)過(guò)河所需要時(shí)間最多的兩個(gè)旅行者送到對(duì)岸去,有兩種方式:

1.最快的和次快的過(guò)河,然后最快的將船劃回來(lái);次慢的和最慢的過(guò)河,然后次快的將船劃回來(lái),所需時(shí)間為:t[0]+2*t[1]+t[n-1];

2.最快的和最慢的過(guò)河,然后最快的將船劃回來(lái),最快的和次慢的過(guò)河,然后最快的將船劃回來(lái),所需時(shí)間為:2*t[0]+t[n-2]+t[n-1]。

算一下就知道,除此之外的其它情況用的時(shí)間一定更多。每次都運(yùn)送耗時(shí)最長(zhǎng)的兩人而不影響其它人,問(wèn)題具有貪心子結(jié)構(gòu)的性質(zhì)。

AC代碼:

#include#includeusing namespace std;
int main(){ int a[1000],t,n,sum; scanf("%d",&t); while(t--) { scanf("%d",&n); sum=0; for(int i=0;iscanf("%d",&a[i]); while(n>3) { sum=min(sum+a[1]+a[0]+a[n-1]+a[1],sum+a[n-1]+a[0]+a[n-2]+a[0]); n-=2; } if(n==3) sum+=a[0]+a[1]+a[2]; else if(n==2) sum+=a[1]; else sum+=a[0]; printf("%d\n",sum); }}


6.區(qū)間覆蓋問(wèn)題


POJ1328是一道經(jīng)典的貪心算法例題。題目大意是假設(shè)海岸線(xiàn)是一條無(wú)限延伸的直線(xiàn)。陸地在海岸線(xiàn)的一側(cè),而海洋在另一側(cè)。每一個(gè)小的島嶼是海洋上的一個(gè)點(diǎn)。雷達(dá)坐落于海岸線(xiàn)上,只能覆蓋d距離,所以如果小島能夠被覆蓋到的話(huà),它們之間的距離最多為d。題目要求計(jì)算出能夠覆蓋給出的所有島嶼的最少雷達(dá)數(shù)目。對(duì)于每個(gè)小島,我們可以計(jì)算出一個(gè)雷達(dá)所在位置的區(qū)間。



問(wèn)題轉(zhuǎn)化為如何用盡可能少的點(diǎn)覆蓋這些區(qū)間。先將所有區(qū)間按照左端點(diǎn)大小排序,初始時(shí)需要一個(gè)點(diǎn)。如果兩個(gè)區(qū)間相交而不重合,我們什么都不需要做;如果一個(gè)區(qū)間完全包含于另外一個(gè)區(qū)間,我們需要更新區(qū)間的右端點(diǎn);如果兩個(gè)區(qū)間不相交,我們需要增加點(diǎn)并更新右端點(diǎn)。

AC代碼:

#include#include#includeusing namespace std;struct Point{ double x; double y;}point[1000];
int cmp(const void *a, const void *b){ return (*(Point *)a).x>(*(Point *)b).x?1:-1;}
int main(){ int n,d; int num=1; while(cin>>n>>d) { int counting=1; if(n==0&&d==0) break; for(int i=0;i { int x,y; cin>>x>>y; if(y>d) { counting=-1; } double t=sqrt(d*d-y*y); //轉(zhuǎn)化為最少區(qū)間的問(wèn)題 point[i].x=x-t; //區(qū)間左端點(diǎn) point[i].y=x+t; //區(qū)間右端點(diǎn) } if(counting!=-1) { qsort(point,n,sizeof(point[0]),cmp); //按區(qū)間左端點(diǎn)排序 double s=point[0].y; //區(qū)間右端點(diǎn) for(int i=1;i { if(point[i].x>s) //如果兩個(gè)區(qū)間沒(méi)有重合,增加雷達(dá)數(shù)目并更新右端點(diǎn) { counting++; s=point[i].y; } else if(point[i].y //如果第二個(gè)區(qū)間被完全包含于第一個(gè)區(qū)間,更新右端點(diǎn) { s=point[i].y; } } } cout<<"Case "<':'<<' '<endl; num++; }}

7.銷(xiāo)售比賽


在學(xué)校OJ上做的一道比較好的題,這里碼一下。假設(shè)有偶數(shù)天,要求每天必須買(mǎi)一件物品或者賣(mài)一件物品,只能選擇一種操作并且不能不選,開(kāi)始手上沒(méi)有這種物品。現(xiàn)在給你每天的物品價(jià)格表,要求計(jì)算最大收益。首先要明白,第一天必須買(mǎi),最后一天必須賣(mài),并且最后手上沒(méi)有物品。那么除了第一天和最后一天之外我們每次取兩天,小的買(mǎi)大的賣(mài),并且把賣(mài)的價(jià)格放進(jìn)一個(gè)最小堆。如果買(mǎi)的價(jià)格比堆頂還大,就交換。這樣我們保證了賣(mài)的價(jià)格總是大于買(mǎi)的價(jià)格,一定能取得最大收益。

#include#include#include#include#include#include#includeusing namespace std;long long int price[100010],t,n,res;
int main(){ ios::sync_with_stdio(false); cin>>t; while(t--) { cin>>n; priority_queue<long long int, vector<long long int>, greater<long long int> > q; res=0; for(int i=1;i<=n;i++) { cin>>price[i]; } res-=price[1]; res+=price[n]; for(int i=2;i<=n-1;i=i+2) { long long int buy=min(price[i],price[i+1]); long long int sell=max(price[i],price[i+1]); if(!q.empty()) { if(buy>q.top()) { res=res-2*q.top()+buy+sell; q.pop(); q.push(buy); q.push(sell); } else { res=res-buy+sell; q.push(sell); } } else { res=res-buy+sell; q.push(sell); } } cout<endl; }}??

下面我們結(jié)合數(shù)據(jù)結(jié)構(gòu)中的知識(shí)講解幾個(gè)例子。

8.Huffman編碼


這同樣是《算法導(dǎo)論》上的例子。Huffman編碼是廣泛用于數(shù)據(jù)文件壓縮的十分有效的編碼方法。我們可以有多種方式表示文件中的信息,如果用01串表示字符,采用定長(zhǎng)編碼表示,則需要3位表示一個(gè)字符,整個(gè)文件編碼需要300000位;采用變長(zhǎng)編碼表示,給頻率高的字符較短的編碼,頻率低的字符較長(zhǎng)的編碼,達(dá)到整體編碼減少的目的,則整個(gè)文件編碼需要(45×1+13×3+12×3+16×3+9×4+5×4)×1000=224000位,由此可見(jiàn),變長(zhǎng)碼比定長(zhǎng)碼方案好,總碼長(zhǎng)減小約25%。


對(duì)每一個(gè)字符規(guī)定一個(gè)01串作為其代碼,并要求任一字符的代碼都不是其他字符代碼的前綴,這種編碼稱(chēng)為前綴碼??赡軣o(wú)前綴碼是一個(gè)更好的名字,但是前綴碼是一致認(rèn)可的標(biāo)準(zhǔn)術(shù)語(yǔ)。編碼的前綴性質(zhì)可以使譯碼非常簡(jiǎn)單:例如001011101可以唯一的分解為0,0,101,1101,因而其譯碼為aabe。譯碼過(guò)程需要方便的取出編碼的前綴,為此可以用二叉樹(shù)作為前綴碼的數(shù)據(jù)結(jié)構(gòu):樹(shù)葉表示給定字符;從樹(shù)根到樹(shù)葉的路徑當(dāng)作該字符的前綴碼;代碼中每一位的0或1分別作為指示某節(jié)點(diǎn)到左兒子或右兒子的路標(biāo)。


從上圖可以看出,最優(yōu)前綴編碼碼的二叉樹(shù)總是一棵完全二叉樹(shù),而定長(zhǎng)編碼的二叉樹(shù)不是一棵完全二叉樹(shù)。給定編碼字符集C及頻率分布f,C的一個(gè)前綴碼編碼方案對(duì)應(yīng)于一棵二叉樹(shù)T。字符c在樹(shù)T中的深度記為dT(c),dT(c)也是字符c的前綴碼長(zhǎng)。則平均碼長(zhǎng)定義為:


使平均碼長(zhǎng)達(dá)到最小的前綴碼編碼方案稱(chēng)為C的最優(yōu)前綴碼。??? ?

Huffman編碼的構(gòu)造方法:先合并最小頻率的2個(gè)字符對(duì)應(yīng)的子樹(shù),計(jì)算合并后的子樹(shù)的頻率;重新排序各個(gè)子樹(shù);對(duì)上述排序后的子樹(shù)序列進(jìn)行合并;重復(fù)上述過(guò)程,將全部結(jié)點(diǎn)合并成1棵完整的二叉樹(shù);對(duì)二叉樹(shù)中的邊賦予0、1,得到各字符的變長(zhǎng)編碼。


POJ3253一道就是利用這一思想的典型例題。題目大意是有把一塊無(wú)限長(zhǎng)的木板鋸成幾塊給定長(zhǎng)度的小木板,每次鋸都需要一定費(fèi)用,費(fèi)用就是當(dāng)前鋸的木板的長(zhǎng)度。給定各個(gè)要求的小木板的長(zhǎng)度以及小木板的個(gè)數(shù),求最小的費(fèi)用。以要求3塊長(zhǎng)度分別為5,8,5的木板為例:先從無(wú)限長(zhǎng)的木板上鋸下長(zhǎng)度為21的木板,花費(fèi)21;再?gòu)拈L(zhǎng)度為21的木板上鋸下長(zhǎng)度為5的木板,花費(fèi)5;再?gòu)拈L(zhǎng)度為16的木板上鋸下長(zhǎng)度為8的木板,花費(fèi)8;總花費(fèi)=21+5+8=34。利用Huffman思想,要使總費(fèi)用最小,那么每次只選取最小長(zhǎng)度的兩塊木板相加,再把這些和累加到總費(fèi)用中即可。為了提高效率,使用優(yōu)先隊(duì)列優(yōu)化,并且還要注意使用long long int保存結(jié)果。

AC代碼:

#include#include#includeusing namespace std;
int main(){ long long int sum; int i,n,t,a,b; while(~scanf("%d",&n)) { priority_queue<int,vector<int>,greater<int> >q; for(i=0;i { scanf("%d",&t); q.push(t); } sum=0; if(q.size()==1) { a=q.top(); sum+=a; q.pop(); } while(q.size()>1) { a=q.top(); q.pop(); b=q.top(); q.pop(); t=a+b; sum+=t; q.push(t); } printf("%lld\n",sum); }}

9.Dijkstra算法


Dijkstra算法是由E.W.Dijkstra于1959年提出,是目前公認(rèn)的最好的求解最短路徑的方法,使用的條件是圖中不能存在負(fù)邊。算法解決的是單個(gè)源點(diǎn)到其他頂點(diǎn)的最短路徑問(wèn)題,其主要特點(diǎn)是每次迭代時(shí)選擇的下一個(gè)頂點(diǎn)是標(biāo)記點(diǎn)之外距離源點(diǎn)最近的頂點(diǎn),簡(jiǎn)單的說(shuō)就是bfs+貪心算法的思想。

#include#include#define INF 1000#define MAX_V 100using namespace std; 
int main(){ int V,E; int i,j,m,n; int cost[MAX_V][MAX_V]; int d[MAX_V]; bool used[MAX_V]; cin>>V>>E; fill(d,d+V+1,INF); fill(used,used+V,false); for(i=0;i { for(j=0;j { if(i==j) cost[i][j]=0; else cost[i][j]=INF; } } for(m=0;m { cin>>i>>j>>cost[i][j]; cost[j][i]=cost[i][j]; } cin>>n; d[n]=0; //源點(diǎn) while(true) { int v=V; for(m=0;m { if((!used[m])&&(d[m] } if(v==V) break; used[v]=true; for(m=0;m { d[m]=min(d[m],d[v]+cost[v][m]); } } for(i=0;i { cout<<"the shortest distance between "<" and "<" is "<endl; }}


10.最小生成樹(shù)算法


設(shè)一個(gè)網(wǎng)絡(luò)表示為無(wú)向連通帶權(quán)圖G =(V, E) , E中每條邊(v,w)的權(quán)為c[v][w]。如果G的子圖G’是一棵包含G的所有頂點(diǎn)的樹(shù),則稱(chēng)G’為G的生成樹(shù)。生成樹(shù)的代價(jià)是指生成樹(shù)上各邊權(quán)的總和,在G的所有生成樹(shù)中,耗費(fèi)最小的生成樹(shù)稱(chēng)為G的最小生成樹(shù)。例如在設(shè)計(jì)通信網(wǎng)絡(luò)時(shí),用圖的頂點(diǎn)表示城市,用邊(v,w)的權(quán)c[v][w]表示建立城市v和城市w之間的通信線(xiàn)路所需的費(fèi)用,最小生成樹(shù)給出建立通信網(wǎng)絡(luò)的最經(jīng)濟(jì)方案。


構(gòu)造最小生成樹(shù)的Kruskal算法和Prim算法都利用了MST(最小生成樹(shù))性質(zhì):設(shè)頂點(diǎn)集U是V的真子集(可以任意選取),如果(u,v)∈E為橫跨點(diǎn)集U和V—U的邊,即u∈U,v∈V- U,并且在所有這樣的邊中,(u,v)的權(quán)c[u][v]最小,則一定存在G的一棵最小生成樹(shù),它以(u,v)為其中一條邊。




使用反證法可以很簡(jiǎn)單的證明此性質(zhì)。假設(shè)對(duì)G的任意一個(gè)最小生成樹(shù)T,針對(duì)點(diǎn)集U和V—U,(u,v)∈E為橫跨這2個(gè)點(diǎn)集的最小權(quán)邊,T不包含該最小權(quán)邊,但T包括節(jié)點(diǎn)u和v。將添加到樹(shù)T中,樹(shù)T將變?yōu)楹芈返淖訄D,并且該回路上有一條不同于的邊,u’∈U,v’∈V-U。將刪去,得到另一個(gè)樹(shù)T’,即樹(shù)T’是通過(guò)將T中的邊替換為得到的。由于這2條邊的耗費(fèi)滿(mǎn)足c[u][v]≤c[u’][v’],故即T’耗費(fèi)≤T的耗費(fèi),這與T是任意最小生成樹(shù)的假設(shè)相矛盾,從而得證。



Prim算法每一步都選擇連接U和V-U的權(quán)值最小的邊加入生成樹(shù)。



#include#include#define MAX_V 100#define INF 1000using namespace std; 
int main(){ int V,E; int i,j,m,n; int cost[MAX_V][MAX_V]; int mincost[MAX_V]; bool used[MAX_V]; cin>>V>>E; fill(mincost,mincost+V+1,INF); fill(used,used+V,false); for(i=0;i { for(j=0;j { if(i==j) cost[i][j]=0; else cost[i][j]=INF; } } for(m=0;m { cin>>i>>j>>cost[i][j]; cost[j][i]=cost[i][j]; } mincost[0]=0; int res=0; while(true) { int v=V; for(m=0;m { if((!used[m])&&(mincost[m] v=m; } if(v==V) break; used[v]=true; res+=mincost[v]; for(m=0;m { mincost[m]=min(mincost[m],cost[v][m]); } } cout<endl;}

Kruskal算法每一步直接將權(quán)值最小的不成環(huán)的邊加入生成樹(shù),我們借助并查集這一數(shù)據(jù)結(jié)構(gòu)可以完美實(shí)現(xiàn)它。



#include#include#define MAX_E 100using namespace std; struct edge{ int u,v,cost; };int pre[MAX_E];edge es[MAX_E];int find(int x);void initvalue(int x);bool same(int x,int y);void unite(int x,int y);bool comp(const edge& e1,const edge& e2);
int main(){ int V,E; int i,j,m,n; cin>>V>>E; initvalue(V); for(i=0;icin>>es[i].u>>es[i].v>>es[i].cost; sort(es,es+E,comp); int res=0; for(i=0;i { edge e=es[i]; if(!same(e.u,e.v)) { unite(e.u,e.v); res+=e.cost; } } cout<endl; }
bool comp(const edge& e1,const edge& e2){ return e1.cost}
void initvalue(int x){ for(int i=0;i}
int find(int x){ int r=x; while(pre[r]!=r) r=pre[r]; int i=x,j; while(pre[i]!=r) { j=pre[i]; pre[i]=r; i=j; } return r;}
bool same(int x,int y){ if(find(x)==find(y)) return true; else return false; }
void unite(int x,int y){ int fx=find(x); int fy=find(y); if(fx!=fy) pre[fx]=fy; }

關(guān)于貪心算法的基礎(chǔ)知識(shí)就簡(jiǎn)要介紹到這里,希望能作為大家繼續(xù)深入學(xué)習(xí)的基礎(chǔ)。
-END-

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀(guān)點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀(guān)點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話(huà)語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉