Új hozzászólás Aktív témák

  • jattila48

    aktív tag

    válasz Boryszka #3095 üzenetére

    Egy mohó algoritmust találtam ki a feladatodra, ami azért nem biztos, hogy optimális megoldást ad. Mintasorozatnak fogom nevezni az 1...N sorozatban bárhol megtalálható eltolt mintát. Tehát az pl. az 1,2,3,4,5,6,7,8 sorozatban az 1,3,4 mintának megfelelő mintasorozatok az 1,3,4; 2,4,5; 3,5,6; 4,6,7 és 5,7,8. Az elgondolás az, hogy a sorozatban megkeresem az első mintasorozatot, majd törlöm az egyik elemét. Ezzel elrontom az éppen aktuális mintasorozatot, és esetleg még másikakat is (legfeljebb annyit, amennyi a minta elemszáma, a példában ez 3). Azt az elemet fogom elhagyni, amelyik a legtöbb mintasorozatot rontja el. Ha több ilyen is van, akkor az elsőt veszem. Ezután az eljárást megismétlem. Megint veszem az első ép mintasorozatot (az elrontottak már nem lesznek tekintetbe véve), és megont elhagyom azt az elemét, amely a legtöbb mintasorozatot rontja el. És így tovább, egészen addig, amíg már nem lesz ép mintasorozat. Írtam is erre egy egyszerű kis programot. Felveszek egy sorozat nevű int tömböt, aminek az i. eleme (0-tól kezdődik az indexelés) kezdetben azt jelzi, hogy az i+1 szám hány mintasorozatban szerepel. A példában ez így néz ki:
    1,1,2,3,3,2,2,1. A 4-es számnak megfelelő érték (3. indexű elem) 3, ami azt jelenti, hogy a 4 3 db mintasorozatban szerepel (1,3,4; 2,4,5; 4,6,7). Ezért az algoritmusnak megfelelően az első kihúzandó szám a 4 lesz. Az 5 is 3 mintasorozatban szerepel, azonban a 4 előbb van, ezért azt választjuk. Ezzel máris elrontottuk a felsorolt 3 mintasorozatot, a továbbiakban ezeket nem vesszük figyelembe. Most a sorozat tömb elemeit csökkenteni fogjuk, annak megfelelően, hogy az egyes számok a még megmaradt mintasorozatok közül hányban szerepelnek. Ezt az eljárást egészen addig ismételjük, amíg a sorozat tömb minden eleme 0 nem lesz.
    A programkód:
    #include <Windows.h>
    #include <stdio.h>

    int main(int argc,char *argv[])
    {
    if(argc<3){
    printf("Hasznalata: mintat_gyomlal <a gyomlalando sorozat hossza> <minta elemek 1... novekvoleg>");
    exit(1);
    }
    int mintahossz=argc-2,sorozathossz=atoi(argv[1]);
    auto minta=new int[mintahossz];
    for(int i=0;i<mintahossz;++i){
    minta[i]=atoi(argv[i+2]);
    }
    int minta_terjedelem=minta[mintahossz-1];
    auto sorozat=new int[sorozathossz];
    for(int i=0;i<sorozathossz;++i){
    sorozat[i]=0;
    }
    for(int i=0;i<=sorozathossz-minta_terjedelem;++i){
    for(int j=0;j<mintahossz;++j){
    ++sorozat[minta[j]+i-1]; //a tomb kezdeti feltotlese. az i.-edik elem azt jelzi, hogy az i+1 szam hany mintasorozatban szerepel
    }
    }
    printf("A sorozatbol kihuzando szamok: ");
    while(1){
    int kihuzando,max=0;
    //megkeressuk az elso, legtobb mintasorozatban szereplo szamot, ez lesz a kihuzando+1 (a kihuzando indexu, mivel 0-val kezdodik az indexeles)
    for(int i=0;i<sorozathossz;++i){
    if(sorozat[i]>max){
    kihuzando=i;
    max=sorozat[i];
    }
    }
    if(max==0)break;
    printf("%d ",kihuzando+1);
    //A kihuzott szam utan a sorozat tomb elemeit csokkentjuk, hogy tovabbra is azt jelezze, a megmaradt ep mintasorozzatok kozul hanyban szerepel az adott szam
    for(int i=0;i<mintahossz;++i){
    int n=kihuzando-minta[i];
    for(int j=0;j<mintahossz;++j){
    int k=minta[j]+n;
    if(k>=0 && sorozat[k]>0){
    --sorozat[k];
    }
    }
    }
    }
    delete[] minta;
    delete[] sorozat;
    }

    Kissé off topic voltam, de ha már itt tetted fel a kérdést, itt válaszoltam. Nem vagyok biztos benne, hogy optimális megoldást ad az algoritmus, de biztosan mintamenteset, és szerintem közel optimálisat. Bár a mohó algoritmusok nem mindig jók. A program egyébként a példára azt fogja kiírni, hogy a 4-et és 5-öt hagyd el, ami jó és optimális is (legalább 2 elemet el kell hagyni). Mivel kezdetben N-mintaterjedelem+1 (mintaterjedelem a legnagyobb, vagyis utolsó mintaelem) mintasorozat van és egy elem kihúzásával legfeljebb nm (minta elemszáma) mintasorozatot rontunk el, ezért legalább (N-mintaterjedelem+1 )/nm felső egész része számú elem kihúzására van szükség. A példában ez 5/3=2, tehát legalább 2 elemet ki kell húzni.

Új hozzászólás Aktív témák