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

Drzewo Sterna-Brocota - szkopuł

HackNation - ogólnopolski hackathon
+1 głos
1,304 wizyt
pytanie zadane 24 czerwca 2023 w C i C++ przez Szyszka Gaduła (3,510 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,510 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,510 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,510 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 (354,880 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,510 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ź 684 wizyt
pytanie zadane 7 czerwca 2023 w C i C++ przez Szyszka Gaduła (3,510 p.)
0 głosów
1 odpowiedź 560 wizyt
pytanie zadane 30 maja 2023 w C i C++ przez Szyszka Gaduła (3,510 p.)
0 głosów
1 odpowiedź 803 wizyt
pytanie zadane 28 maja 2023 w C i C++ przez Szyszka Gaduła (3,510 p.)

93,626 zapytań

142,549 odpowiedzi

323,034 komentarzy

63,129 pasjonatów

Advent of Code 2025

Top 15 użytkowników

  1. 1452p. - dia-Chann
  2. 1437p. - DziarnowskiJ
  3. 1411p. - Łukasz Piwowar
  4. 1409p. - CC PL
  5. 1371p. - raydeal
  6. 1275p. - Maurycy W
  7. 1254p. - Adrian Wieprzkowicz
  8. 1219p. - robwarsz
  9. 1141p. - ssynowiec
  10. 1134p. - Tomasz Bielak
  11. 1116p. - rucin93
  12. 1100p. - Mariusz Fornal
  13. 885p. - Dominik Łempicki (kapitan)
  14. 847p. - Grzegorz Aleksander Klementowski
  15. 838p. - Wojciech Malicki
Szczegóły i pełne wyniki

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

Kursy INF.02 i INF.03
...