• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Drzewo Sterna-Brocota - szkopuł

+1 głos
1,517 wizyt
pytanie zadane 24 czerwca 2023 w C i C++ przez Szyszka Gaduła (3,530 p.)

Witam.

Chciałem rozwiązać zadanie: https://szkopul.edu.pl/problemset/problem/zFA7joqxZZ9lbwA0FoqjmZwP/site/?key=submissions

I to jest mój kod:

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

std::pair<uint32_t, uint32_t> read_fraction(const std::string& fraction) {
	uint32_t i = 0;
	uint32_t nominator = 0;
	while (fraction[i] != '/') {
		nominator = nominator * 10 + (fraction[i] - '0');
		i++;
	}

	// Omit the '/'
	i++;

	uint32_t denominator = 0;
	while (i < fraction.size()) {
		denominator = denominator * 10 + (fraction[i] - '0');
		i++;
	}

	return std::make_pair(nominator, denominator);
}

int main()
{
	uint32_t n;
	std::cin >> n;

	std::vector<std::string> level{"0/1", "1/0"};
	std::vector<std::string> next_level(3);
	for (uint32_t i = 0; i < n; i++) {
		uint32_t added = 0;
		for (uint32_t j = 0; j < level.size() - 1; j++) {
			next_level[j + added] = level[j];

			std::pair<uint32_t, uint32_t> left = read_fraction(level[j]);
			std::pair<uint32_t, uint32_t> right = read_fraction(level[j + 1]);

			std::string result = std::to_string(left.first + right.first) + "/" + std::to_string(left.second + right.second);
			next_level[j + added + 1] = result;
			added++;
		}

		next_level[level.size() - 1 + added] = level[level.size() - 1];
		level = next_level;
		next_level.erase(next_level.begin(), next_level.end());
		next_level.resize(level.size() * 2 - 1);
	}

	for (const std::string& fraction : level)
		std::cout << fraction << " ";

	return 0;
}

Ale niestety nie mogę zaliczyć ostatniego testu, bo zużywam zbyt dużo pamięci. Właściwie zauważyłem że wystarczy około 5s i już zużywam 400mb. Przechowuję tylko ostatni level i kolejny, żeby właśnie tej pamięci oszczędzić. Co tu mogę jeszcze poprawić, żeby zaliczyć na 100?

W tagach zadania wskazane jest użycie rekurencji - ale czy to tylko nie pogorszy problemu z pamięcią? Poza tym takie rozwiązanie wydaje mi się trudniejsze

komentarz 25 czerwca 2023 przez Szyszka Gaduła (3,530 p.)
Jakąś wizję już mam, ale po 1. nie mam kompletnie pomysłu na przypadek podstawowy, a po 2. w którym momencie mogę wypisać ułamek? https://pastebin.com/R4dGGBnp

Jeśli w ogóle będę w którymś momencie wypisywał któryś ułamek - to zawsze będą duplikaty (jeśli dobrze myślę). A czy w ogóle podejście jest dobre? Najpierw liczę wszystkie ułamki dla lewego i potem wszystkie dla lewego i tego nowo powstałego, a potem tak samo dla prawego.
komentarz 25 czerwca 2023 przez Whistleroosh Maniak (57,400 p.)
1. Spójrz na liczbe n i co ona oznacza

2. Podejście jest dobre. Spójrz na kod który wysłałem wczesniej on dokładnie rozwiązuje ten problem
komentarz 25 czerwca 2023 przez Szyszka Gaduła (3,530 p.)
Ok, mam takie coś: https://pastebin.com/Ki3Sr1nX

Oczywiście nie działa. Mój max który konstruuje w main mówi ile elementów musi się znaleźć w ostatnim levelu drzewa.

Rozumiem, że po 1 jest problem z synchronizacją tego count (ta gałąź która pójdzie na lewo i na prawo się nie dogadują, jakby liczone jest dwa razy więcej niż potrzeba jeśli dobrze myślę). Ale jest też jakiś inny problem, bo nawet jak zrobiłem count jako zmienną globalną to i tak źle działało.
komentarz 25 czerwca 2023 przez Whistleroosh Maniak (57,400 p.)
Jest dobrze tylko max jest za duży. To nie powinna być liczba elementów na levelu
komentarz 25 czerwca 2023 przez Szyszka Gaduła (3,530 p.)
Aha. Zrobiłem max jako n i działa. Jeszcze nie kumam czemu ale jak rozrysuje to może się dowiem.

2 odpowiedzi

+1 głos
odpowiedź 28 czerwca 2023 przez Eriss69 Gaduła (4,470 p.)
#include <iostream>
#include <vector>
#include <string>
 
std::pair<uint32_t, uint32_t> read_fraction(const std::string& fraction) {
    uint32_t i = 0;
    uint32_t nominator = 0;
    while (fraction[i] != '/') {
        nominator = nominator * 10 + (fraction[i] - '0');
        i++;
    }
 
    // Omit the '/'
    i++;
 
    uint32_t denominator = 0;
    while (i < fraction.size()) {
        denominator = denominator * 10 + (fraction[i] - '0');
        i++;
    }
 
    return std::make_pair(nominator, denominator);
}
 
int main()
{
    uint32_t n;
    std::cin >> n;
 
    std::vector<std::string> level{"0/1", "1/0"};
 
    for (uint32_t i = 0; i < n; i++) {
        std::vector<std::string> next_level(level.size() * 2 - 1);
        uint32_t added = 0;
 
        for (uint32_t j = 0; j < level.size() - 1; j++) {
            next_level[j + added] = level[j];
 
            std::pair<uint32_t, uint32_t> left = read_fraction(level[j]);
            std::pair<uint32_t, uint32_t> right = read_fraction(level[j + 1]);
 
            std::string result = std::to_string(left.first + right.first) + "/" + std::to_string(left.second + right.second);
            next_level[j + added + 1] = result;
            added++;
        }
 
        next_level[level.size() - 1 + added] = level[level.size() - 1];
        level = std::move(next_level);
    }
 
    for (const std::string& fraction : level)
        std::cout << fraction << " ";
 
    return 0;
}
  1. Zamiast tworzyć kopię wektora next_level, użyłem semantyki przenoszenia (std::move) do przeniesienia zawartości next_level do level. Działa to szybciej i zużywa mniej pamięci.

    pozdrawiam

0 głosów
odpowiedź 24 czerwca 2023 przez adrian17 Mentor (355,180 p.)
Hmm, czemu w vectorach przechowujesz stringi, po czym z powrotem rozpakowujesz je do pary?

Na intuicję, przechowywanie par w vectorach i wyrzucenie stringów powinno poprawić zużycie pamięci (i czas) dobrych kilka razy.
komentarz 24 czerwca 2023 przez Szyszka Gaduła (3,530 p.)
Nie wiem czemu, chyba zamknąłem się w jakiejś dziwnej bańce podczas pisania xD. Czas jest sporo krótszy, zużycie pamięci też, ale to wciąż za mało dla ostatniego testu. Tak to wygląda obecnie: https://pastebin.com/gvHrbm1a

Podobne pytania

+1 głos
1 odpowiedź 841 wizyt
pytanie zadane 7 czerwca 2023 w C i C++ przez Szyszka Gaduła (3,530 p.)
0 głosów
1 odpowiedź 769 wizyt
pytanie zadane 30 maja 2023 w C i C++ przez Szyszka Gaduła (3,530 p.)
0 głosów
1 odpowiedź 961 wizyt
pytanie zadane 28 maja 2023 w C i C++ przez Szyszka Gaduła (3,530 p.)

93,731 zapytań

142,668 odpowiedzi

323,286 komentarzy

63,290 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...