Zadanie JLITOSL ze SPOJ'a - drobny problem z kodem // C++

Odpowiedz Nowy wątek
2019-09-06 19:09
0

Cześć. Napisałem rozwiązanie zadania ze SPOJ'a: https://pl.spoj.com/problems/JLITOSL/ . Kod działa poprawnie dla liczb, które skladaja sie z trzycyfrowych segmentów cyfr od 1 do 9. W przypadku pojawienia się w rozpatrywanej liczbie zera lub gdy ilość cyfr w rozpatrywanej liczbie nie jest podzielna przez 3, pojawiają się dodatkowe spacje (liczba 013 jest przekształcana na "_trzynascie"). Byłbym wdzięczny za wskazówki, jak pozbyć się tych dodatkowych spacji z outputu mojego kodu...

http://ideone.com/m7IcHP

#include <iostream>
#include <map>
#include <vector>
#include <string>

using namespace std;

string zamienNaSlowo (int liczba)
{
    map <int, string> zapisSlowny;
    zapisSlowny [1] = "jeden";
    zapisSlowny [2] = "dwa";
    zapisSlowny [3] = "trzy";
    zapisSlowny [4] = "cztery";
    zapisSlowny [5] = "piec";
    zapisSlowny [6] = "szesc";
    zapisSlowny [7] = "siedem";
    zapisSlowny [8] = "osiem";
    zapisSlowny [9] = "dziewiec";
    zapisSlowny [10] = "dziesiec";
    zapisSlowny [11] = "jedenascie";
    zapisSlowny [12] = "dwanascie";
    zapisSlowny [13] = "trzynascie";
    zapisSlowny [14] = "czternascie";
    zapisSlowny [15] = "pietnascie";
    zapisSlowny [16] = "szesnascie";
    zapisSlowny [17] = "siedemnascie";
    zapisSlowny [18] = "osiemnascie";
    zapisSlowny [19] = "dziewietnascie";
    zapisSlowny [20] = "dwadziescia";
    zapisSlowny [30] = "trzydziesci";
    zapisSlowny [40] = "czterdziesci";
    zapisSlowny [50] = "piecdziesiat";
    zapisSlowny [60] = "szescdziesiat";
    zapisSlowny [70] = "siedemdziesiat";
    zapisSlowny [80] = "osiemdziesiat";
    zapisSlowny [90] = "dziewiecdziesiat";
    zapisSlowny [100] = "sto";
    zapisSlowny [200] = "dwiescie";
    zapisSlowny [300] = "trzysta";
    zapisSlowny [400] = "czterysta";
    zapisSlowny [500] = "piecset";
    zapisSlowny [600] = "szescset";
    zapisSlowny [700] = "siedemset";
    zapisSlowny [800] = "osiemset";
    zapisSlowny [900] = "dziewiecset";

    string slowo;
    map <int,string>::iterator it = zapisSlowny.find(liczba);

    if (it != zapisSlowny.end())
    {
        slowo = it->second;
    }
    return slowo;
}

void zamienLiczbeTrzycyfrowaNaSlowo(int liczbaTrzycyfrowa)
{
    int tymczasowa1, tymczasowa2 = 0;
    tymczasowa1 = liczbaTrzycyfrowa % 100;
    tymczasowa2 = liczbaTrzycyfrowa % 10;
    liczbaTrzycyfrowa = liczbaTrzycyfrowa - tymczasowa1;

    if (zamienNaSlowo(liczbaTrzycyfrowa) != " ")
        cout << zamienNaSlowo(liczbaTrzycyfrowa) << " ";

    if (tymczasowa1 < 20)
        cout << zamienNaSlowo(tymczasowa1);
    else
    {
        tymczasowa2 = tymczasowa1 % 10;
        tymczasowa1 = tymczasowa1 - tymczasowa2;

        if (zamienNaSlowo(tymczasowa1) != " ")
            cout << zamienNaSlowo(tymczasowa1) << " ";

        cout << zamienNaSlowo(tymczasowa2);
    }
}

vector <string> podzielStringNaCiagiTrzycyfrowe (string &liczba)
{
    const int dlugoscPodciagu = 3;
    int dlugoscLiczby = liczba.length();
    int liczbaPodciagow = dlugoscLiczby / dlugoscPodciagu;

    vector <string> wektorCiagowTrzycyfrowych;

    for (int i=liczbaPodciagow-1; i>=0; i--)
    {
        wektorCiagowTrzycyfrowych.push_back(liczba.substr(i*dlugoscPodciagu + dlugoscLiczby%dlugoscPodciagu, dlugoscPodciagu));
    }

    if (dlugoscLiczby % dlugoscPodciagu != 0)
        wektorCiagowTrzycyfrowych.push_back(liczba.substr(0,dlugoscLiczby%dlugoscPodciagu));

    return wektorCiagowTrzycyfrowych;
}

vector <int> zamienCiagiZnakowNaLiczby (vector<string> &wektorCiagowTrzycyfrowych)
{
    vector <int> wektorLiczbTrzycyfrowych;
    int dlugoscWektora = wektorCiagowTrzycyfrowych.size();

    for (int i=0; i<dlugoscWektora; i++)
        wektorLiczbTrzycyfrowych.push_back(stoi(wektorCiagowTrzycyfrowych [i]));

    return wektorLiczbTrzycyfrowych;
}

void zamienWektorNaZapisSlowny (vector <int> &wektorLiczbTrzycyfrowych)
{
    int dlugoscWektora = wektorLiczbTrzycyfrowych.size();
    string rzadWielkosci [5] = {" ","tys. ","mln. ","mld. ","bln. "};

    for (int i=dlugoscWektora-1; i>=0; i--)
    {
        zamienLiczbeTrzycyfrowaNaSlowo (wektorLiczbTrzycyfrowych[i]);
        cout << " " << rzadWielkosci [i];
    }
    cout << endl;
}

int main()
{
    int liczbaTestow;
    string liczba;

    cin >> liczbaTestow;

    for (int i=0; i<liczbaTestow; i++)
    {
        cin >> liczba;

        vector <string> wektorCiagowTrzycyfrowych = podzielStringNaCiagiTrzycyfrowe(liczba);
        vector <int> wektorLiczbTrzycyfrowych = zamienCiagiZnakowNaLiczby(wektorCiagowTrzycyfrowych);
        zamienWektorNaZapisSlowny (wektorLiczbTrzycyfrowych);
    }
    return 0;
}
edytowany 1x, ostatnio: kq, 2019-09-06 19:10

Pozostało 580 znaków

2019-09-06 19:27
0

Ja bym to zrobił inaczej, nie dzielił liczby na segmenty trzycyfrowe, tylko odcinał od końca po trzy cyfry (modulo 1000), przekształcał taką liczbę i pushował string do listy (żeby nie trzeba było odwracać), na koniec wydrukował listę po linijce.


edytowany 2x, ostatnio: lion137, 2019-09-06 19:44

Pozostało 580 znaków

2019-09-06 19:40
0
lion137 napisał(a):

Ja bym to zrobił inaczej, nie dzielił liczby na segmenty trzycyfrowe, tylko odcinał(czyli odejmował tą resztę), od końca po trzy cyfry (modulo 1000), przekształcał taką liczbę i pushował string do listy (żeby nie trzeba było odwracać), na koniec wydrukował listę po linijce.

Dzięki, tylko czy to rozwiąże mój problem? Wydaje mi się, że istota całego problemu leży w funkcji przekształcającej trzycyfrowe ciągi, niezależnie od tego w jaki sposób zostały pozyskane z wyjściowego stringa? Upewniłem się, że mój kod poprawnie wyodrębnia segmenty, tj liczbę np. 12120012 dzieli na 12, 120 oraz 012. Tylko teraz jak zamienić to 012 na "dwanaście" a nie na " dwanascie" (z dodatkową spacją z przodu)

Pozostało 580 znaków

2019-09-06 19:47
0

Na początek: nie odejmował (wtedy jest błąd), tylko ręcznie odcinał po trzy cyfry, zedytowałem post. A właśnie tak jak napisałem; liczba 12120012 będzie przetwarzana: 12, 120, 12. W każdym kroku: modulo 1000 i oderwanie trzech cyfr.


edytowany 1x, ostatnio: lion137, 2019-09-06 19:48

Pozostało 580 znaków

2019-09-06 20:11
0

Tzn. ja zrozumiałem, co miałeś na myśli za pierwszym razem - że modulo ładnie wydzieli mi poszczególne liczby bez zera wiodącego. Z tym się zgadzam jak najbardziej i jest to fajny sposób, który wykorzystam na etapie optymalizacji, gdyby były problemy z przekroczeniem czasu. Tylko wciąz potrzebna jest funkcja przekształcająca liczby max trzycyfrowe na ich zapis slowny, a w mojej funkcji jest błąd, którego póki co nie mogę się pozbyć.

Mój program przekształca wszystkie liczby od 1 do 99 dodając tę nieszczęsną spację z przodu. Jeśli na inpucie programu wprowadzę np. "12", program w obecnej postaci przekształca mi to nie na "dwanaście" tylko na "_dwanaście". Taka sama sytuacja pojawia sie, gdy wprowadzę liczbę "012" - output to "_dwanascie". Podobnie "1" oraz "001" obie zwracają "_jeden". Ale gdy wprowadzam jakąkolwiek liczbę od 100 do 999, program zamienia ją jak należy.

Tu tkwi istota mojego problemu - poszukuję sposobu poprawienia funkcji przekształcającej liczby max 3-cyfrowe na słowa w przypadku, gdy te liczby składają się z jednej lub dwóch cyfr (albo mają z przodu jedno lub dwa zera).

edytowany 1x, ostatnio: Aurigo, 2019-09-06 20:12

Pozostało 580 znaków

2019-09-06 20:23

Acha, ale przecież, już praktycznie, Masz rozwiązanie, Stablicowałeś od 0 do 20 i "pełne dziesiątki"; to teraz nie Dodawaj tego "underscore", tylko inne dwucyfrowe Zamieniaj bezpośrednio (x to liczba): jak nie jest w słowniku, to: lewa cyfra (x / 10), jak 2 to "dwadzieścia", i tak dalej i prawa cyfra (x mod 10) to "jeden", "dwa", ... Oczywiście, "krańcowy" przypader zera Masz załatwiony (string pusty, tak mi się wydaje wynika z opisu zadania).


edytowany 1x, ostatnio: lion137, 2019-09-06 20:24

Pozostało 580 znaków

2019-09-06 20:34
0

Zrobiłem takiego facepalma, że aż mi czerwony ślad został na pysku... ;p Oczywiście masz racje, rozwiązanie jest dużo prostsze niz mi się wydawało. Chyba zmęczenie tematem dało mi się już we znaki i wywołało takiego brain farta... Dzięki śliczne za podpowiedż!

Proszę bardzo. Przestań, całe życie to seria facepalmów, za pięc lat Będziesz się z tego śmiał, robiąc jeszcze większe :-D:-D - lion137 2019-09-06 20:37

Pozostało 580 znaków

2019-09-09 11:50
3

Offtopic:
Ta mapa jest niezbyt dobrze zdefiniowana. Zkładając, że masz C++11 lepiej było by tak:

string zamienNaSlowo(int liczba)
{
    static const map <int, string> zapisSlowny {
        { 1, "jeden" },
        { 2, "dwa" },
        { 3, "trzy" },
        { 4, "cztery" },
        { 5, "piec" },
        { 6, "szesc" },
        { 7, "siedem" },
        { 8, "osiem" },
        { 9, "dziewiec" },
        { 10, "dziesiec" },
        { 11, "jedenascie" },
        { 12, "dwanascie" },
        { 13, "trzynascie" },
        { 14, "czternascie" },
        { 15, "pietnascie" },
        { 16, "szesnascie" },
        { 17, "siedemnascie" },
        { 18, "osiemnascie" },
        { 19, "dziewietnascie" },
        { 20, "dwadziescia" },
        { 30, "trzydziesci" },
        { 40, "czterdziesci" },
        { 50, "piecdziesiat" },
        { 60, "szescdziesiat" },
        { 70, "siedemdziesiat" },
        { 80, "osiemdziesiat" },
        { 90, "dziewiecdziesiat" },
        { 100, "sto" },
        { 200, "dwiescie" },
        { 300, "trzysta" },
        { 400, "czterysta" },
        { 500, "piecset" },
        { 600, "szescset" },
        { 700, "siedemset" },
        { 800, "osiemset" },
        { 900, "dziewiecset" },
    };

    string slowo;
    auto it = zapisSlowny.find(liczba);

    if (it != zapisSlowny.end())
    {
        slowo = it->second;
    }
    return slowo;
}

http://ideone.com/A0B9OE

Należy wyraźnie pochwalić bardzo dobrze zadane pytanie (nie wiem co poprawił kq, ale za pewne to było tylko drobne niedociągnięcie).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
FYI: skopiowałem kod z ideone na forum i chyba nic więcej. Nie widzę wklejonych linków do poradników, więc musiało być dobrze :​) - kq 2019-09-09 12:46

Pozostało 580 znaków

2019-09-09 14:36
0

Dzięki za wskazówkę, będę o tym pamiętał przy kolejnym programie z mapą!

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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