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

Zadanie Tamy - algorytmika

Aruba Cloud VPS - 50% taniej przez 3 miesiące!
0 głosów
411 wizyt
pytanie zadane 7 sierpnia 2023 w C i C++ przez VNC Nowicjusz (240 p.)

Mam takie zadanie z III etapu V OIG:

Tamy

Limit pamięci: 64 MB

W Bajtocji zbudowano wielki zbiornik wodny. Podzielono go na pewną liczbę jednakowej długości sektorów. Pomiędzy każdymi dwoma sąsiednimi sektorami znalazła się tama o pewnej wysokości. Tamy zbudowano także przed pierwszym oraz za ostatnim sektorem.

Obecnie poziom wody w całym zbiorniku jest taki sam. Ponieważ jednak zaczął padać ulewny deszcz, poziom wody zaczął szybko wzrastać. Król Bajtocji chce wiedzieć, ile czasu upłynie, zanim woda przeleje się przez pierwszą lub przez ostatnią tamę, wskutek czego pewnikiem dojdzie do zalania Bajtocji. Obliczenie tego utrudnia fakt, że nad każdym z sektorów deszcz może padać z różną intensywnością.

Pomóż królowi obliczyć czas, jaki pozostał do wylania się wody poza zbiornik. Jeżeli poziom wody jest równy dokładnie wysokości tamy, woda jeszcze się nie wylewa. Gdy część zbiornika już zalana wodą jest ograniczona z obu stron tamami tej samej wysokości, woda przelewa się z niej w obie strony równie szybko.

Wejście

Pierwszy wiersz standardowego wejścia zawiera jedną liczbę całkowitą image (image), oznaczającą liczbę sektorów, na jakie podzielony jest zbiornik.

Drugi wiersz zawiera ciąg image liczb całkowitych image (image) pooddzielanych pojedynczymi odstępami, oznaczających wysokości (ponad początkowy poziom wody) kolejnych tam.

Trzeci wiersz zawiera ciąg image liczb całkowitych image (image) pooddzielanych pojedynczymi odstępami, oznaczających, o ile poziomów woda podnosi się w image-tym sektorze w ciągu jednej sekundy.

Możesz założyć, że w testach wartych przynajmniej image punktów wysokości tam są parami różne. Ponadto, w części tych testów, wartych co najmniej image punktów, zachodzi warunek image.

Wyjście

Pierwszy wiersz standardowego wyjścia powinien zawierać jedną liczbę całkowitą, będącą najmniejszą liczbą całkowitą nie mniejszą niż liczba sekund, po których woda wyleje się ze zbiornika.

Przykład

Dla danych wejściowych:

4
3 5 2 6 4
1 3 3 1

image

poprawną odpowiedzią jest:

2

 

Generalnie to przeczytalem pomysl wzorcowy na to zadanie, ale gdzies w implementacji mam blad i zadanie przechodzi tylko na 18 punktow. Czy bylby ktos w stanie mi pomoc go znalezc? Oto moj kod:

#include<bits/stdc++.h>

using namespace std;

vector<int> tamy;
vector<double> przyrost;
vector<pair<double, double>> dane;
vector<double> czas;

struct Node{
	double czas;
	double indx;
	double ile_odjete;
	Node(double p_czas, double p_indx, double p_ile_odjete): czas(p_czas), indx(p_indx), ile_odjete(p_ile_odjete) {}
};

class Kopiec{
	public:
		double czas_all=0;
		vector<Node> tablica = vector<Node>(1, Node(0, 0, 0));

		void wstaw(Node e){
			tablica.push_back(e);
			int w = tablica.size()-1;
			while(w > 1 && tablica[w].czas < tablica[w/2].czas){
				swap(tablica[w], tablica[w/2]);
				w/=2;
			}
		}
		
		void przywroc(int i){
			int lewy = 2*i;
			int prawy = 2*i+1;
			int maks = i;
			
			if(lewy < tablica.size() && tablica[lewy].czas<tablica[maks].czas)
				maks = lewy;
			if(prawy < tablica.size() && tablica[prawy].czas<tablica[maks].czas)
				maks = prawy;
			if(maks > i){
				swap(tablica[i], tablica[maks]);
				przywroc(maks);
			}
		}
		
		void buduj(){
			for(int i = tablica.size()/2; i >= 1; i--)
				przywroc(i);
		}
		
		void usun(){
			tablica[1]=tablica[tablica.size()-1];
			tablica.pop_back();
			przywroc(1);
		}
		
		void przelej_lewo(bool czyObieStrony){
				int it=tablica[1].indx-1;
				while(it >= 0 && przyrost[it]==-1)
					it--;
				
				double v = przyrost[it]*czas_all;
				przyrost[it] += dane[tablica[1].indx].first/dane[it].second;
				dane[it].first+=dane[tablica[1].indx].first;
				if(czyObieStrony){
					przyrost[it]/=2;
					dane[it].first/=2;
				}
				przyrost[tablica[1].indx] = -1;
				usun();
				uaktualnij_czas();
				czas[it]=(tamy[it]-v)/przyrost[it];		
				wstaw(Node((tamy[it]-v)/przyrost[it], it, czas_all));
				
		}
		void przelej_prawo(bool czyObieStrony){
				int it=tablica[1].indx+1;
				while(it < przyrost.size() && przyrost[it]==-1)
					it++;
					
				double v = przyrost[it]*czas_all;
				przyrost[it] += dane[tablica[1].indx].first/dane[it].second;
				dane[it].first+=dane[tablica[1].indx].first;
				if(czyObieStrony){
					przyrost[it]/=2;
					dane[it].first/=2;
				}
				przyrost[tablica[1].indx] = -1;
				usun();
				uaktualnij_czas();	
				czas[it]=(tamy[it+1]-v)/przyrost[it];	
				wstaw(Node((tamy[it+1]-v)/przyrost[it], it, czas_all));
		}
		
		void uaktualnij_czas(){
			if(tablica.size() >= 4){
				for(int i=1; i<4; i++){
					if(tablica[i].czas==czas[tablica[i].indx]){
						tablica[i].czas = tablica[i].czas-(czas_all-tablica[i].ile_odjete);
						tablica[i].ile_odjete=czas_all;
						czas[tablica[i].indx] = tablica[i].czas;	
					}
				}
			}
			else{
				for(int i=1; i<tablica.size(); i++){
					if(tablica[i].czas==czas[tablica[i].indx]){
						tablica[i].czas = tablica[i].czas-(czas_all-tablica[i].ile_odjete);
						tablica[i].ile_odjete=czas_all;
						czas[tablica[i].indx] = tablica[i].czas;	
					}
				}
			}
			przywroc(1);
		}
		
		bool ruch(){
			if(tablica.size()==1)
				return true;		
			
			if(tablica[1].czas!=czas[tablica[1].indx]){
				tablica[1]=tablica[tablica.size()-1];
				tablica.pop_back();
				przywroc(1);
				return false;
			}
			
			czas_all += tablica[1].czas;
			
			if(tablica[1].czas == tamy[0]/przyrost[0] || tablica[1].czas == tamy[tamy.size()-1]/przyrost[przyrost.size()-1])
				return true;
			if(tablica[1].indx==0 || tablica[1].indx==przyrost.size()-1)
				return true;

			if(tamy[tablica[1].indx] < tamy[tablica[1].indx+1])
				przelej_lewo(false);
			else if(tamy[tablica[1].indx] > tamy[tablica[1].indx+1])
				przelej_prawo(false);
			else{
				przelej_lewo(true);
				przelej_prawo(true);
			}
			
			return false;
		}
};



int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n; cin >> n;
int tamy_wczytane[n+1];
int przyrost_wczytane[n];
for(int i=0; i<n+1; i++)
	cin >> tamy_wczytane[i];
for(int i=0; i<n; i++)
	cin >> przyrost_wczytane[i];


pair<int, int> maks = make_pair(0, 0);
for(int i=0; i<n+1; i++){
	if(maks.first < tamy_wczytane[i])
		maks = make_pair(tamy_wczytane[i], i);
}


double suma=0;
double it=0;
tamy.push_back(tamy_wczytane[0]);
for(int i=1; i<=maks.second; i++){
	if(tamy_wczytane[i] >= tamy[tamy.size()-1]){
		tamy.push_back(tamy_wczytane[i]);
		it++;
		suma+=przyrost_wczytane[i-1];
		dane.push_back(make_pair(suma, it));
		przyrost.push_back(suma/it);
		it=0;
		suma=0;
	}
	else{
		suma+=przyrost_wczytane[i-1];
		it++;
	}
		
}

it=0;
suma=0;
stack<int> stos_tamy;
stack<double> stos_przyrost;
stack<pair<int, int>> stos_dane;
if(n!=maks.second)
	stos_tamy.push(tamy_wczytane[n]);
for(int i=n-1; i>=maks.second; i--){
	int top = stos_tamy.top();
	if(tamy_wczytane[i] >= top){
		suma+=przyrost_wczytane[i];
		it++;	
		if(i!=maks.second)stos_tamy.push(tamy_wczytane[i]);
		stos_przyrost.push(suma/it);
		stos_dane.push(make_pair(suma, it));
		it=0;
		suma=0;
	}
	else{
		suma+=przyrost_wczytane[i];
		it++;	
	}	
}
if(it!=0){
	stos_przyrost.push(suma/it);
	stos_dane.push(make_pair(suma, it));
}
	

while(!stos_tamy.empty()){
	int top = stos_tamy.top();
	tamy.push_back(top);
	stos_tamy.pop();
}
while(!stos_przyrost.empty()){
	double top = stos_przyrost.top();
	przyrost.push_back(top);
	stos_przyrost.pop();
}
while(!stos_dane.empty()){
	pair<int, int> top = stos_dane.top();
	dane.push_back(top);
	stos_dane.pop();
}

Kopiec* kopiec_lewy = new Kopiec;
Kopiec* kopiec_prawy = new Kopiec;
bool mode = true;
for(int i=0; i<przyrost.size(); i++){
	if(tamy[i] == maks.first)
		mode=false;
	if(mode){
		int h = min(tamy[i], tamy[i+1]);
		kopiec_lewy->tablica.push_back(Node(h/przyrost[i], i, 0));
		czas.push_back(h/przyrost[i]);	
	}
	else{
		int h = min(tamy[i], tamy[i+1]);
		kopiec_prawy->tablica.push_back(Node(h/przyrost[i], i, 0));
		czas.push_back(h/przyrost[i]);
	}

}
kopiec_lewy->buduj();
kopiec_prawy->buduj();

while(!kopiec_lewy->ruch());
while(!kopiec_prawy->ruch());

if(kopiec_lewy->czas_all==0){
	if(kopiec_prawy->czas_all!=int(kopiec_prawy->czas_all))
		kopiec_prawy->czas_all=ceil(kopiec_prawy->czas_all);
	else
		kopiec_prawy->czas_all++;
	cout << kopiec_prawy->czas_all<< endl;
	delete kopiec_lewy;
	delete kopiec_prawy;
	return 0;
}
else if(kopiec_prawy->czas_all==0){
	if(kopiec_lewy->czas_all!=int(kopiec_lewy->czas_all))
		kopiec_lewy->czas_all=ceil(kopiec_lewy->czas_all);
	else
		kopiec_lewy->czas_all++;
	cout << kopiec_lewy->czas_all << endl;
	delete kopiec_lewy;
	delete kopiec_prawy;
	return 0;
}

if(kopiec_lewy->czas_all!=int(kopiec_lewy->czas_all))
	kopiec_lewy->czas_all=ceil(kopiec_lewy->czas_all);
else
	kopiec_lewy->czas_all++;

if(kopiec_prawy->czas_all!=int(kopiec_prawy->czas_all))
	kopiec_prawy->czas_all=ceil(kopiec_prawy->czas_all);
else
	kopiec_prawy->czas_all++;

cout << min(kopiec_lewy->czas_all, kopiec_prawy->czas_all) << endl;

	
delete kopiec_lewy;
delete kopiec_prawy;
return 0;	
}

Z gory dziekuje za wszystkie odpowiedzi

komentarz 7 sierpnia 2023 przez reaktywny Nałogowiec (44,490 p.)
Nie wczytałem się w Twój program, ale jest na moje oko mocno zbyt rozbudowany jak na tak stosunkowo prosty problem. Kod jest b. długi, wygląda jak source code Windowsa 3.1 ;)

Przedstawiony problem jest dość trywialny i oklepany, w kilku różnych wersjach pojawia się na stronach typu LeetCode i innych.
komentarz 7 sierpnia 2023 przez pasjonat_algorytmiki Pasjonat (19,540 p.)

@VNC, 

Obawiam się, że niestety może nie być osoby, która Ci pomoże z tym kodem, bo jest on bardzo skomplikowany i szukanie błędu jest bardzo ciężkie.

komentarz 8 sierpnia 2023 przez reaktywny Nałogowiec (44,490 p.)
Przykładowo metody przelej_lewo i przelej_prawo można zastąpić jedną przelej. Ten kod można sporo uprościć i skrócić.

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
1 odpowiedź 186 wizyt
pytanie zadane 21 sierpnia 2023 w C i C++ przez VNC Nowicjusz (240 p.)
0 głosów
2 odpowiedzi 234 wizyt
pytanie zadane 29 października 2023 w C i C++ przez VNC Nowicjusz (240 p.)
0 głosów
2 odpowiedzi 939 wizyt

93,164 zapytań

142,175 odpowiedzi

321,927 komentarzy

62,491 pasjonatów

Advent of Code 2024

Top 15 użytkowników

  1. 682p. - dia-Chann
  2. 670p. - CC PL
  3. 669p. - Łukasz Piwowar
  4. 656p. - Łukasz Eckert
  5. 567p. - ssynowiec
  6. 453p. - Marcin Putra
  7. 428p. - rafalszastok
  8. 423p. - Michal Drewniak
  9. 423p. - Adrian Wieprzkowicz
  10. 418p. - rucin93
  11. 415p. - Mikbac
  12. 410p. - Piotr Aleksandrowicz
  13. 408p. - ksalekk
  14. 402p. - Mariusz Fornal
  15. 401p. - Dawid128
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

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...