Teknologian jakaminen

"Algoritmihuomautukset" yhteenveto nro 6 - Ahne

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Yksinkertainen ahneus

        ahne menetelmäSe on eräänlainen ratkaisuOptimointi ongelma Tämä menetelmä ottaa aina huomioon strategian saavuttaa optimaalinen (tai parempi) globaali tulos nykytilan paikallisen optimaalisen (tai paremman) jälkeen. On selvää, että jos valitaan parempi, mutta ei optimaalinen strategia (optimaalista strategiaa ei ehkä ole olemassa tai sitä ei ole helppo ajatella), saatu globaali tulos ei voi olla optimaalinen.Optimaalisen tuloksen saavuttamiseksi jokaisen välivaiheen strategian on oltava optimaalinen, joten ongelman ratkaisemiseen käytetään tiukasti ahnetta menetelmää.optimoida Kysymys edellyttää valitun strategian perusteluja. Todistuksen yleinen ajatus on käyttää todistetta ristiriidalla ja matemaattisella induktiolla, eli olettaen, että strategia ei voi johtaa optimaaliseen ratkaisuun, ja saada sitten ristiriita sarjan johdolla todistamaan, että strategia on optimaalinen. , ja lopuksi käytä matemaattista induktiota globaalin optimin varmistamiseksi. Päivittäisessä käytössä ei kuitenkaan välttämättä ole aikaa tai helppoa todistaa tiukasti mieleen tulevaa strategiaa (ahneuden todistaminen on usein vaikeampaa kuin itse ahneus), joten yleisesti ottaen, jos ajattelet toteuttamiskelpoiselta vaikuttavaa strategiaa, Ja jos et voi antaa vastaesimerkkiä, ole tarpeeksi rohkea toteuttamaan se.

1. Ryhmittele pienin numero

Kun numerot ovat 0–9, voit järjestää nämä numerot mihin tahansa järjestykseen, mutta sinun on käytettävä niitä kaikkia ja tehtävä mahdollisimman pieni kohdenumero (0 ei tietenkään voi olla ensimmäinen, esimerkiksi Enter). kaksi 0:ta, kaksi 1:tä, kolme 5:tä ja An 8:a, pienin saatu luku on 100155858.


Uskon, että voit nähdä strategian heti: valitse ensin pienin luku, joka ei ole 0, 1-9 tulostettavaksi, ja tulosta sitten numerot 0-9. Kunkin luvun tulosteiden lukumäärä on sen jäljellä oleva luku.

Todiste oikeasta strategiasta

  • Ensinnäkin, koska kaikkien numeroiden on osallistuttava yhdistelmään, lopputuloksen numeroiden lukumäärä määritetään.
  • Koska suurin bitti ei ole 0, valitse ensimmäiseksi bitiksi mahdollisimman pieni luku - korkeimman bitin lause
  • Loput numerot tulee myös tulostaa pienistä suuriin~

Oppikirjan teksti on todella liian abstrakti ja näyttää olevan hieman väärä.

  1. #include <cstdio>
  2. #include <vector>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. int main() {
  7. vector<int> V;
  8. for(int i=1;i<=10;i++)
  9. {
  10. int temp=0;
  11. cin>>temp;
  12. V.push_back(temp);
  13. }
  14. sort(V.begin(),V.end()); //直接排成升序
  15. int flag=0; //标记
  16. for(int i=0;i<=9;i++)
  17. if(V[i]!=0)
  18. {
  19. int temp=V[i];
  20. V[i]=V[0];
  21. V[0]=temp;
  22. flag=i;//保存第一个不为0的位置
  23. break;
  24. }
  25. for(int i=flag+1;i<=9;i++) //找更小的头,直接从flag下一位开始即可,节省时间~
  26. if(V[i]<V[0]&&V[i]!=0)
  27. {
  28. int temp=V[i];
  29. V[i]=V[0];
  30. V[0]=temp;
  31. }
  32. for(int i=0;i<=9;i++)
  33. cout<<V[i];
  34. }

Loogisesti se ei ole vaikeaa, tärkeintä on ajatella selkeästi~

2. Mooncake inventaario

  • Syötä N ja M ensimmäiselle riville: N-numeroinen kuukakkutyyppien määrä ja M-numeroinen markkinakysyntä on syötettävä kahdelle seuraavalle riville: ensimmäisellä rivillä olevat N numerot vastaavat nykyiset tyypit Kuinka paljon voit ansaita kaikkien kuukakkujen myynnin jälkeen, ja toisella rivillä oleva N-luku vastaa nykyistä kuukakkujen kokonaismäärää~.
  • Vaadittu tuotos: enimmäistulo määrätyllä kysynnällä

Kuvittele vain, jos olisit pomo, kuinka olisit "ahne"? Ilmeisesti - jos vain rajoitetun kysynnän puitteissa pitäisi myydä mahdollisimman monta kuukakkua kalleimmalla yksikköhinnalla, eikö olisi mahdollista kerätä suurinta liikevaihtoa? Seuraava on bloggaajan itsensä kirjoittama toteutus, joka eroaa oppikirjassa olevasta:

  1. #include <cstdio>
  2. #include <vector>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. struct mooncake{
  7. double num; //总数
  8. double income; //总收入
  9. double price; //单价,需要自己计算
  10. };
  11. int main() {
  12. int N,M;
  13. cin>>N>>M;
  14. vector<mooncake> V;
  15. for(int i=1;i<=N;i++)
  16. {
  17. mooncake temp;
  18. V.push_back(temp);
  19. }
  20. cout<<"请输入数量:"<<endl;
  21. for(int i=1;i<=N;i++)
  22. {
  23. double num=0;
  24. cin>>num;
  25. V[i-1].num=num;
  26. }
  27. cout<<"请输入总价:"<<endl;
  28. for(int i=1;i<=N;i++)
  29. {
  30. double income=0;
  31. cin>>income;
  32. V[i-1].income=income;
  33. }
  34. for(int i=0;i<=N-1;i++)
  35. V[i].price=V[i].income/V[i].num; //计算单价
  36. //按单价降序排列!保证贵的尽可能多卖
  37. for(int i=0;i<=V.size()-1;i++)
  38. {
  39. for(int j=i;j<=V.size()-1;j++)
  40. if(V[j].price>V[i].price)
  41. {
  42. mooncake temp;
  43. temp=V[j];
  44. V[j]=V[i];
  45. V[i]=temp;
  46. }
  47. }
  48. for(int i=0;i<=V.size()-1;i++)
  49. cout<<"单价第"<<(i+1)<<"高的值为:"<<V[i].income<<" "<<V[i].price<<" "<<V[i].num<<endl;
  50. for(int i=0;i<=N-1;i++)
  51. cout<<V[i].num<<endl;
  52. int j=0; //使用的下标
  53. double count=0; //总利润
  54. while(M>0) //当还有需求量时
  55. {
  56. double doubt=0;
  57. doubt=M-V[j].num; //用M减去当前类型的额总量
  58. if(doubt>=0)//减了以后M还有剩余
  59. {
  60. M-=V[j].num;//当前种类全部卖出
  61. count+=V[j].income;//直接总价相加
  62. j++;
  63. cout<<V[j].num;
  64. }
  65. else if(doubt<0) //不够减这么多
  66. {
  67. count+=V[j].price*M;//剩余部分按照单价计算
  68. break;
  69. }
  70. }
  71. cout<<"最高利润值为:"<<count<<endl;
  72. return 0;
  73. }

Maista varovasti whlie-silmukkaa yllä olevassa: kun M ei ole 0 - eli kysyntää on vielä, myy kalleimmat kuukakut. Myy yksitellen järjestyksessä: Jos nykyinen kysyntä riittää myymään kaikki nykyiset tyypit, kokonaishinta lisätään suoraan, jos se ei riitä kaikkien nykyisten myymiseen, niin myy niin monta kuin on ovat ja lasketaan yksikköhinnan perusteella~

Testataan sitä oppikirjan testitapauksella:

  • 3 20
  • 18 15 10
  • 75 72 45

Tulos on 94,50, mikä vastaa standardivastausta~

Lisäksi bloggaaja kirjoittaa lajittelun suoraan pääfunktioon, kirjoittaa sen itsenäiseksi funktioksi ja sitten kutsuu sen rakennetyyppisessä vektorissa, ja lajittelu ei onnistu syystä, voit kirjoittaa sen kommenttikenttään~

2. Intervalliahne

Kysymysvarsi on seuraava:

Tämän tyyppistä kysymystä varten sinun tarvitsee vain muistaa...Anna etusija aikavälille, jolla on suurempi vasen päätepiste

 

Puhutaanpa siitä, miksi teemme tämän, kuten yllä olevassa kuvassa näkyy: sitä ei ole vaikea löytää,Varmistaaksemme mahdollisimman monta vaihtoehtoa, kun pidempi aikaväli sisältää lyhyemmän välin, meidän on ensin valittava lyhin väli, tämä on helppo ymmärtää.

Yllä olevassa tilanteessa, kuten päällekkäisissä intervalleissa, kuten 1 ja 2, ei ole vaikeaa havaita, että jos valitset intervallin 1, jolla on suurin vasen päätepiste, se on vain paikan 9, kun taas jos valitset intervallin 2, se varaa. Asema 8. Asema - Tämä ei tietenkään ole sopusoinnussa ajatuksen kanssa mahdollisimman vähän rahankäytöstä (vähemmän tilan käyttäminen), joten kannattaa valita mahdollisimman kauas vasemmalle, jotta tyhjää tilaa jää enemmän oikealla ~ kuten yllä,Näemme käsin laskemalla, että hajanaisia ​​on enintään 4.

Koodi oppikirjasta:

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. const int maxn=110;
  5. struct Inteval{
  6. int x,y; //开区间左右端点
  7. }I[maxn];
  8. bool cmp(Inteval a,Inteval b)
  9. {
  10. if(a.x!=b.x)
  11. return a.x>b.x; //左端点从大到小排序
  12. else
  13. return a.y<b.y; //左端点相同的按右端点从小到大排序
  14. }
  15. int main() {
  16. int n;
  17. while(scanf("%d",&n,n!=0))
  18. {
  19. for(int i=0;i<n;i++)
  20. scanf("%d%d",&I[i].x,&I[i].y);
  21. sort(I,I+n,cmp); //排序区间
  22. int ans=1,lastX=I[0].x;
  23. //ans记录总数,lastX记录上一个被选择的区间的左端点
  24. for(int i=1;i<n;i++)
  25. {
  26. if(I[i].y<=lastX) //如果该区间右端点在lastX左边
  27. {
  28. lastX=I[i].x; //以I[i]作为新选中的区间
  29. ans++; //不相交的区间个数+1
  30. }
  31. }
  32. printf("%dn",ans);
  33. }
  34. return 0;
  35. }

Bloggaajat eivät kuitenkaan edelleenkään pidä alkuperäisistä taulukoista. Tässä on vektorirakenneversio:

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;
  5. struct section{
  6. int x=0;
  7. int y=0;
  8. //x和y分别为左右端点
  9. };
  10. int main() {
  11. int n=0;
  12. vector<section> V;
  13. cin>>n;
  14. for(int i=1;i<=n;i++) //读入数据
  15. {
  16. section temp;
  17. int x=0,y=0;
  18. cin>>x>>y;
  19. if(x>y) //防止左端点大于右端点
  20. {
  21. int temp1=x;
  22. x=y;
  23. y=temp1;
  24. }
  25. else if(x==y) //若左右端点相同
  26. {
  27. i-=1; //则当前输入 不算
  28. cout<<"不可以输入相同的左右端点!"<<endl;
  29. continue; //舍弃数据,本次循环作废~
  30. }
  31. temp.x=x;
  32. temp.y=y;
  33. V.push_back(temp);
  34. }
  35. //按要求排序区间优先级
  36. for(int i=0;i<=V.size()-1;i++)
  37. {
  38. for(int j=i+1;j<=V.size()-1;j++)
  39. {
  40. if(V[j].x>V[i].x) //左端点越大越靠前
  41. {
  42. section temp=V[j];
  43. V[j]=V[i];
  44. V[i]=temp;
  45. }
  46. else if(V[j].x==V[i].x&&V[j].y<V[i].y) //左端点相同的话,右端点小的优先
  47. {
  48. section temp=V[j];
  49. V[j]=V[i];
  50. V[i]=temp;
  51. }
  52. }
  53. }
  54. cout<<"顺序如下:"<<endl;
  55. for(int i=0;i<=V.size()-1;i++)
  56. cout<<V[i].x<<"~"<<V[i].y<<endl;
  57. int count=1,lastX=V[0].x;
  58. //count用来统计总数,lastX是上一个符合条件的区间的左端点
  59. for(int i=1;i<=V.size()-1;i++)//直接从第二个区间开始
  60. {
  61. if(V[i].y<lastX) //如果当前区间的右端点不和上一个左端点相加,满足题意
  62. {
  63. lastX=V[i].x;
  64. count++;
  65. }
  66. }
  67. cout<<count<<endl;
  68. return 0;
  69. }

Testi on seuraava:

 


Yleensä ahne menetelmä on algoritminen idea, jota käytetään eräänlaisen optimointiongelman ratkaisemiseen ja joka toivoo saavansa globaalin optimaalisen tuloksen paikallisesta optimaalisesta strategiasta.ahne algoritmi Sovellettavien ongelmien tulee täyttää optimaalisen alirakenteen ominaisuudet, eli sen osaongelmien optimaalisista ratkaisuista voidaan rakentaa tehokkaasti optimaalinen ongelman ratkaisu. Ilmeisesti kaikki ongelmat eivät sovellu ahneelle menetelmälle, mutta tämä ei estä ahneesta algoritmista muodostumasta yksinkertainen, käytännöllinen ja tehokas algoritmi~