Anagram do 5 literowego wyrazu.

0

Stworzyłem program wypisujący wszystkie anagramy do słowa "kogut", jednakowoż nie działa tak jak powinien. Wyświetla prawidłową ich liczbę 120, jednak litery się powtarzają i nie wszystkie wyrazy mają 5 znaków.
Poniżej podaję kod i serdecznie proszę o poprawę programu :

 #include <iostream>

using namespace std;
char napis[6]="kogut";
int main()
{
    int i1, i2, i3, i4, i5;
    int b=0;
    for (i1=0; i1<5; i1++)
    {
        for(i2=0; i2<5; i2++)
        {
            if(i1==i2) continue;
            for(i3=0; i3<5; i3++)
            {

                if(i3==i1 || i3==i2) continue;
                for(i4=0; i4<5; i4++)
                {
                    if(i4==i1 || i4 ==i2 || i4==i3) continue;
                    i5=7-i1-i2-i3-i4;
                    b++;
                    cout <<b<<" "<< napis[i1] << napis[i2] << napis[i3] << napis[i4] << napis[i5] << endl;

                }
            }
        }
    }
    return 0;
}

1

Dlaczego uważasz, że i5=7-i1-i2-i3-i4; ma Ci dać pozostały indeks? Weź np. sytuację gdy i1=5 a i2=4. Już wtedy, bez względu na pozostałe indeksy wartość i5 wynosi -2.
Propozycje:

  1. Dopisać taką samą pętlę po 5 - albo w jakiś inny sposób wybrać 5 element - głupie rozwiązanie.
  2. Wywalić wszystko, poszukać w necie jak zrobili to inni - popatrzeć na funkcję next_permutation - dobre rozwiązanie.
0

Problem rozwiązany. Dziękuje szweszwe za wskazanie "feleru".
Dodałem kolejną pętlę zamiast
i5=7+i1-i2-i3-i4;

#include <iostream>

using namespace std;
char napis[6]="kogut";
int main()
{
    int i1, i2, i3, i4, i5 ,b;
     b=0;
         for (i1=0; i1<5; i1++) // pierwsza litera
    {
        for(i2=0; i2<5; i2++) // druga litera
        {
            if(i1==i2) continue;
            for(i3=0; i3<5; i3++) //trzecia litera
            {
                if(i3==i1 || i3==i2) continue;
                for(i4=0; i4<5; i4++) //czwarta litera
                {
                    if(i4==i1 || i4 ==i2 || i4==i3) continue;
                    for (i5=0 ; i5<5;i5++)
                       {

                        if (i5==i1 || i5==i2 ||i5==i3 || i5==i4)  continue;
                         b++;

                        cout << napis[i1] << napis[i2] << napis[i3] << napis[i4] << napis[i5] <<"   " <<b << endl;

                       }
                }
            }
        }
    }
    return 0;
}

2

Już co najmniej drugi raz widzę tutaj na forum kod wyznaczający anagramy, na podstawie hardkodowanych (zagnieżdżonych) pętli i kupki warunków. O ile dobrze napisany w ten sposób algorytm będzie działać prawidłowo, to jest całkowicie bezużyteczny - ogranicza się do ciągów wejściowych o określonej z góry długości.

Jeśli zdołałeś poprawić program i teraz działa prawidłowo to plus dla Ciebie. Jednak jeżeli chcesz troszkę poćwiczyć to możesz spróbować użyć do tego celu rekurencji. Przy czym wykluczenie możliwości wielokrotnego użycia tego samego znaku tylko uprości implementację :]

0

Program ten potrzebuję do jednokrotnego użytku i tylko na 5 liter ale stworzenie "modowalnego" programu tworzącego anagramy nie jest złym pomysłem. W przyszłości postaram się taki stworzyć ale na ten moment obawiam się że nie potrafię :F

2

Nie znam prawie w ogóle C++, ale mogę pokazać przykład w innym języku:

type
  TCharset = set of AnsiChar;

  procedure Anagram(const ACharset: TCharset; const AValue: String = '');
  var
    LChar: AnsiChar;
  begin
    if ACharset = [] then
      WriteLn(AValue)
    else
      for LChar in ACharset do
        Anagram(ACharset - [LChar], AValue + LChar);
  end;

  procedure PrintAnagrams(const AValue: String);
  var
    LCharset: TCharset = [];
    LChar: AnsiChar;
  begin
    for LChar in AValue do
      LCharset += [LChar];
      
    Anagram(LCharset);
  end;

To są zwykłe dwie procedury - PrintAnagrams jest do wywołania przez użytkownika, a Anagram to procedurka rekurencyjna. Przykład wywołania oraz wygenerowane wyjście znajdują się na ideone.com. Plusem tego kodu jest generowanie anagramów z jednoczesnym ich sortowaniem alfabetycznym - to zasługa zbiorów, więc sortowanie mamy w prezencie. Minusem - również za sprawą zbiorów - jest brak obsługi wejściowych ciągów, w których dana literka występuje kilka razy. Ale to tylko przykład.

Głównie chodzi o to, aby w pierwszym parametrze rekurencyjnej metody podać zestaw znaków, a w drugim uzupełniany ciąg znaków. Czyli pierwszy argument to znaki jeszcze możliwe do wykorzystania, a drugi to ciąg zbudowany z już użytych znaków. Każde kolejne rekurencyjne wywołanie oznacza przekazanie w pierwszym parametrze zbioru znaków bez aktualnie używanego (iterator pętli) oraz w drugim parametrze bieżący ciąg znaków plus znak z pętli.

To tylko wzorzec rekurencyjnego generowania anagramów, więc jeśli chcesz się trochę pobawić i poćwiczyć to spróbuj napisać odpowiednik w C++.

1

Przeszukałem internet odnośnie polecenia next_permutation, i okazało się że stworzenie elastycznego programu jest wiele prostsze:

 #include <algorithm>
#include <string>
#include <iostream>
 
int main()
{
    std::string s = "kogut";
    std::sort(s.begin(), s.end());
    do {
        std::cout << s << '\n';
    } while(std::next_permutation(s.begin(), s.end()));
}

Jeśli ktoś chce więcej poczytać: http://en.cppreference.com/w/cpp/algorithm/next_permutation

dzięki za pomoc ^^

1 użytkowników online, w tym zalogowanych: 0, gości: 1