Afişează mesaje
|
|
Pagini: [1] 2
|
|
1
|
infoarena - concursuri, probleme, evaluator, articole / Arhiva de probleme / Răspuns: 474 Teams
|
: Martie 18, 2013, 13:23:49
|
Am inteles. Cred ca evaluarea tine cont de timpul de citire/scriere, asa ca un cod simplu, cum ar fi cel de mai jos, n-ar trebui sa afecteze evaluarea. Incadrarea in limitele impuse trebuie sa vina din algoritm. // citire ifstream is( "teams.in" ); is >> N >> A >> B; for ( i = 0; i < N; ++i ) { is >> x; if ( x < B ) ++c[ v[j++] = x ]; // aici lucrurile sunt amestecate putin: nu este numai citire; este implementata si o parte din algoritm }
// algoritm // ...
// scriere ofstream( "teams.out" ) << s / 2;
Desigur, se poate recurge la “parsareâ€, si am pus ghilimele pentru ca nu e o parsare adevarata, dar asta ar insemna ca a fost folosita o smecherie: nu a fost modificat algoritmul propriu-zis. Daca "parsarea" e folosita doar pentru a micsora timpul de executie, nu pentru a te incadra in timpul impus, atunci cred ca metoda poate fi acceptata. Cred ca am inteles si care sunt standardele impuse pentru astfel de probleme: foarte relaxate. Intr-un mediu real ar trebui, de exemplu sa verifici limitele, sa folosesti alocare dinamica, tabele de asociere, etc. “Parsareaâ€, asa cum am vazut-o eu in codul din arhiva, e o smecherie: presupune ca datele de intrare sunt formate din cifre si spatii, lucru care in realitate este de neacceptat: in fisierul de intrare poate fi orice, nu ce ne imaginam noi ca ar trebui sa fie. Si ca sa vezi cat de reala e problema, cineva a postat mai sus un set de date de intrare presupus corect, dar care este in afara limitelor date de probleme: este inclusa si valoarea zero, desi valoarea minima este 1. Rezultatul obtinut de cel ce a postat setul a fost confirmat si de o alta persoana, desi setul este gresit. Succes si mult sport.
|
|
|
|
|
2
|
infoarena - concursuri, probleme, evaluator, articole / Arhiva de probleme / Răspuns: 474 Teams
|
: Martie 05, 2013, 23:42:14
|
Poate cineva să-mi arate o citire completă cu parsare ?  (de la declararea fișierelor) Ai mutat intrebarea. Incerc sa-ti raspund la intrebarea originala. Nu cunosc problema. Parsarea unui fisier presupune utilizarea unui scanner (sau analizor lexical); scannerul sparge streamul de intrare in lexeme (token-uri sau cuvinte). De exemplu, sirul " 1234 test" poate fi vazut, din punct de vedere al lexemelor, astfel: "numar identificator". Urmatorul exemplu foloseste un scanner ce intoarce doua tipuri de lexeme: intreg si caracter. Apoi scannerul este folosit pentru a afisa doar numerle. #include <fstream> #include <string> #include <iostream>
using namespace std;
// doua tipuri de lexeme (token): intreg si caracter plus sfarsit de stream enum lexeme_kind { lexeme_eof, lexeme_char, lexeme_int };
// lexema contine tipul si valoarea struct lexeme { lexeme_kind k; union { int i; char c; } v; lexeme( int ai ) { k = lexeme_int; v.i = ai; } lexeme( char ac ) { k = lexeme_char; v.c = ac; } lexeme() { k = lexeme_eof; } };
// lexeme last_lexeme;
// "scanner" (citeste urmatoarea lexema din stream) lexeme get_lexeme( istream& is ) { char c; // ignora whitespace ws( is );
// is.get( c ); if ( ! is ) return last_lexeme = lexeme(); // eof sau error
// daca este numar (ignoram numerele ce incep cu '+' sau '-') if ( isdigit( c ) ) { string s; s += c; while ( is.get( c ) && isdigit( c ) ) s += c; is.putback( c ); return last_lexeme = lexeme( atoi( s.c_str() ) ); }
// nu e numar return last_lexeme = lexeme( c ); }
int main() { // ifstream is( "test.txt" ); if ( ! is ) return -1;
// citeste lexemele si afiseaza doar numerele while ( get_lexeme( is ).k != lexeme_eof ) switch ( last_lexeme.k ) { case lexeme_int: cout << last_lexeme.v.i << endl; break; case lexeme_char: break; default: return -2; // lexema necunoscuta }
return 0; }
P.S. Am citit enuntul. Sunt nedumerit. Cum s-a ajuns la probleme legate de parsare?!
|
|
|
|
|
3
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Lucrul cu fisiere
|
: Martie 05, 2013, 17:32:35
|
Corect: sare peste "whitespaces" (blanc, tab, CR, NL). Se poate rescrie asa: while ( is.get( c ) ) { // ...
sau asa (mai complicat): is >> noskipws; while ( is >> c ) { // ...
Codul in care folosesc break mi s-a parut mai usor de inteles decat varianta originala si este mai usor de inteles si decat codul de mai jos (care respecta teorema programarii structurate): is >> noskipws; while ( is >> c && c != '\n' ) { // ...
sau while ( is.get( c ) && c != '\n' ) { // ...
|
|
|
|
|
4
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Lucrul cu fisiere
|
: Martie 05, 2013, 14:15:57
|
Scuzati-mi insistenta si poate greutatea cu care am inteles.
N-ai pentru ce-ti cere scuze. Nimeni nu s-a nascut invatat iar fara efort ma indoiesc ca poti realiza ceva. Textul problemei este interpretabil. De exemplu, daca numarul randului ar fi fost specificat, atunci ar fi trebuit sa numeri caracterele "new-line" (sau altul care desemneaza sfarsitul de linie, in functie de formatul fisierului). Cum randul nu este specificat, poate ca vrea o functie care sa ia ca argument numarul randului. Poti anticipa gradul de complexitate al exercitiului in functie de cunostintele predate pana acum. Daca ultima lectie se refera la codurile ASCII, atunci poate ca profesorul se asteapta sa folosesti comparatii in loc de "toupper". Si tot asa. O ultima observatie legata de codul postat de Razvan. Daca ati invata despre "break", poate fi rescris asa: char c; bool is_even = false; while ( is >> c ) // cat timp pot citi din fisierul de intrare { if ( c == '\n' ) break; // iesi din bucla // ... }
Adica, nu e nevoie de niciun "get". Spor la invatat.
|
|
|
|
|
6
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Lucrul cu fisiere
|
: Martie 04, 2013, 17:48:41
|
- " a[256];" Nu ai nevoie de niciun vector. Citesti caracterul, il convertesti, daca-i cazul si il afisezi. - " fstream f1("exemplu.txt",ios::in);" De ce nu ai folosit "ifstream is("exemplu.txt");"? In mod traditional un stream de intrare se noteaza cu "is". - " f1>>sir" Citeste din f1 pana la primul blanc (exclusiv) - " a=(int)sir;" Ce ai vrut sa faci aici? O rezolvare posibila: #include <fstream> #include <iostream>
using namespace std;
int main() { ifstream is( "exemplu.txt" ); if ( ! is ) return -1; // eroare la deschidere (fisierul nu a fost gasit, de exemplu)
char c; bool is_even = false; while ( is >> c ) // cat timp pot citi din fisierul de intrare { if ( is_even ) cout << char( toupper( c ) ); is_even = ! is_even; }
return 0; }
|
|
|
|
|
9
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Robot
|
: Martie 01, 2013, 13:05:40
|
In cazul asta, felicitari. Implementarea pare a fi foarte simpla. Ce faci acolo semana cu “breadth-frist searchâ€. O sa revad enuntul, daca gasesc timp. Cel mai simplu ar fi sa intrerupi executia, daca depasesti limitele, si sa afisezi un mesaj de eroare; sau poti folosi coada standard <queue> (mai lenta). ... Am gasit ceva timp si am implementat cum m-am priceput. Nu am participat la vreun concurs, asa ca nu prea stiu care sunt cerintele. Se pare ca este incurajata folosirea variabilelor globale si a numelor criptice. Copiaza codul pe calculatorul tau si vezi ce iese. #include <time.h> #include <fstream> #include <iostream> using namespace std;
// i este indexul randului; intodeauna // j este indexul coloanei; intodeauna
// energia maxima #define EMAX 30000
// numarul maxim de randuri #define RMAX 200
// numarul maxim de coloane #define CMAX 200
// energia intiala int p;
// numarul de randuri int n;
// numarul de coloane int m;
// tabla de joc int c[RMAX][CMAX];
// celulele vizitate char v[RMAX][CMAX];
// starea robotului struct t_state { int r; // rand int c; // coloana int ec; // energie celula int er; // energie robot void set( int ar, int ac, int aec, int aer ) { r = ar; c = ac; ec = aec; er = aer; } };
// coada de stari intermediare t_state q[RMAX*CMAX]; // datele int dq; // indexul de extrage (deque) int eq; // indexul de inserare (enque)
// solutii int s[CMAX]; int ns; // numar solutii
// int global_bytes_count() { return sizeof( p ) + sizeof( n ) + sizeof( m ) + sizeof( c ) + sizeof( v ) + sizeof( q ) + sizeof( dq ) + sizeof( eq ) + sizeof( s ) + sizeof( ns ); }
// bool read() { ifstream is( "robot.in" ); if ( ! is ) return false;
if ( ! ( is >> p >> n >> m ) ) return false;
for ( int i = 0; i < n; ++i ) for ( int j = 0; j < m; ++j ) if ( ! ( is >> c[i][j] ) ) return false;
return true; }
// bool write() { ofstream os( "robot.out" ); if ( ! os ) return false;
if ( ns < 1 ) { if ( ! ( os << -1 ) ) return false; } else { for ( int i = 0; i < ns; ++i ) if ( ! (os << s[i] << ' ' ) ) return false; }
return true; }
// find_path implementeaza algoritmul "breadth-first search" // cu o definitie alternativa a adiacentei data de consumul de energie: // daca consumul este prea mare, celula nu este adiacenta // (vezi Introduction to Algorithms, Cormen et alii) bool find_path( int j ) { // reseteaza celulele vizitate memset( v, 0, sizeof(v) );
// reseteaza coada dq = eq = 0;
// adauga pozitia initiala q[eq++].set( 0, j, c[0][j], p );
// marcheaza pozitia initiala v[0][j] = 1; // cat timp coada nu e goala while ( eq - dq > 0 ) { // extrage din coada int tq = dq++;
// daca am ajuns la ultimul rand if ( q[tq].r >= n - 1 ) return true;
// examineaza celulele adiacente int i = q[tq].r + 1; // randul adiacent int pc = ( q[tq].c <= 0 ) ? 0 : -1; // prima coloana relativ la pozitia curenta int uc = ( q[tq].c <= m - 2 ) ? 1 : 0; // ultima coloana relativ la pozitia curenta for ( int k = pc; k <= uc; ++k ) // coloanele adiacente relativ la coloana curenta { // coloana adiacenta int j = q[tq].c + k; // care ar fi energia robotului daca s-ar muta pe celula adiacenta int er = q[tq].er - abs( c[i][j] - q[tq].ec ); if ( er <= 0 ) continue; // toata energia ar fi consumata: celula nu e "adiacenta"
// celula adiacenta // daca celula nu este vizitata if ( ! v[i][j] ) { // insereaza in coada q[eq++].set( i, j, c[i][j], er ); // marcheaza v[i][j] = 1; } } }
// nu a fost gasit niciun drum return false; }
// void run() { // initializeaza numarul de solutii ns = 0;
// cauta drumul pentru fiecare coloana for ( int j = 0; j < m; ++j ) if ( find_path( j ) ) s[ns++] = j + 1; }
// void print_gmem_info() { #ifndef NDEBUG cout << "Memorie globala consumata: " << double( global_bytes_count() ) / 1024 / 1024 << " MB" << endl; #endif }
// numarul de executii pentru benchmark #define XMAX 100000
// afiseaza durata total a executiilor #define BENCHMARK
int main() { print_gmem_info();
if ( ! read() ) { cerr << "Eroare la citire"; return -1; }
#ifdef BENCHMARK clock_t t0 = clock(); for ( int k = 0; k < XMAX; ++k ) #endif
run();
#ifdef BENCHMARK clock_t d = clock() - t0; cout << "Durata pentru " << XMAX << " executii: " << double(d)/CLOCKS_PER_SEC << "s" << endl; #endif
if ( ! write() ) { cerr << "Eroare la scriere"; return -2; }
return 0; }
|
|
|
|
|
10
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Răspuns: Robot
|
: Martie 01, 2013, 00:04:38
|
|
Felicitari pentru participarea la olimpiada.
- [...puţină memorie şi are un timp de execuţie cât mai mic.] Inainte de orice, trebuie sa te preocupe corectitudinea rezultatului. - [...E ceva greşit dacă îi zic "coadă" ?] Nu; e foarte bine, doar ca nu am vazut-o. Nu-mi aduc aminte de algoritm; au trecut ceva ani de cand am terminat scoala. - [Pe viitor o să folosesc comentarii.] Comentariile te ajuta. - [...am făcut o greşeală gravă.] N-as zice. - [...nu credeam că e o greşeală gravă] N-ai putea compila codul pe compilatoare mai noi. - M-am uitat inca o data la programel si nu am inteles ce urmaresti, asa ca l-am compilat. Pentru setul de mai jos am obtinut: 1 2 3 4. Este corect? 100 4 4 10 80 60 90 100 100 100 50 200 100 100 60 300 500 200 100
|
|
|
|
|
11
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Robot
|
: Februarie 28, 2013, 01:02:35
|
|
- Cerinta nu pomeneste nimica de optimal (si cred ca nu aveti cunostinele necesare). - Nu am inteles la ce foloseste "coada" (si nici de ce ii zici "coada"). - Ce faci daca drumul pe care esti consuma toata energia dar exista altul bun (cu acelasi punct de pornire)? - Foloseste comentarii. - bool p[dim] = {false}; initializeaza primul element, nu tot vectorul. Asta a fost intentia? - main fara int in fata violeaza standardul curent.
|
|
|
|
|
12
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Divide et Impera
|
: Februarie 27, 2013, 13:33:26
|
Cine naiba scrie manualele astea? Sunt de o absurditate strigatoare la cer.
Nu stiu... Pare a fi cea mai simpla problema ce ilustreaza algoritmul, dar cred ca nu se poate rezolva fara a sti cate ceva despre <string>. Pe de alta parte, sper ca la momentul angajarii, elevul de acum sa stie ca nu asa se inverseaza un sir; sa stie ca exista metode mult mai putin costisitoare.
|
|
|
|
|
13
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Divide et Impera
|
: Februarie 26, 2013, 22:21:20
|
Am vorbit despre această idee de rezolvare la ora de info,am convenit că nu implică "Divide et Impera".
Asa e. M-am uitat intr-o carte de algoritmi si nu este conform definitiei. Implementarea de mai jos este conform definitiei (desi absurd de costisitoare). #include <string> // ... string reverse( string s ) { if ( s.size() < 2 ) return s; // am ajuns la baza // subproblema "stanga" string l = reverse( s.substr( s.size() / 2, s.size() - 1 ) ); // subproblema "dreapta" string r = reverse( s.substr( 0, s.size() / 2 ) ); // combinarea celor doua solutii string c = l + r; return c; }
Definitia zice cam asa: - problema trebuie rezolvata recursiv - la fiecare nivel se parcurg urmatorii pasi: o " Divide" problema curenta se divide in cel putin doua subprobleme. o " Impera" subproblemele sunt rezolvate recursiv. o Rezultatele subproblemelor sunt combinate rezultand solutia problemei curente.
|
|
|
|
|
14
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Divide et Impera
|
: Februarie 26, 2013, 18:31:00
|
void reverse( char* s , int i, int j ) { if ( i < j ) { std::swap( s[i], s[j] ); reverse( s, i+1, j-1 ); } }
Cred ca o astfel de cerinta are doar scop educativ. In lumea reala poate ca ar arata asa: void reverse( char* s ) { if ( ! s ) return; char* e = s; while ( *e ) ++e; for ( --e; s < e; ++s, --e ) { char t = *s; *s = *e; *e = t; } }
Succes.
|
|
|
|
|
17
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Memorie/complexitate
|
: Februarie 17, 2013, 20:04:29
|
si pentru complexitate ? eu programez in pascal:d
Nu am folosit Pascal de foarte mult timp. Pot spune ca nu mai stiu nimica. In general, din punctul de vedere al complexitatii algoritmului, ar trebui sa le vezi la fel. In realitate alocarea pe heap necesita un timp mai mare (ce nu poate fi controlat de client). Imagineaza-ti ca ai un raft de cutii inchise si-ti trebuie o cutie goala; stii ca exista, dar nu stii unde: poate-i prima, poate-i ultima.
|
|
|
|
|
19
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Răspuns: Memorie/complexitate
|
: Februarie 17, 2013, 19:45:03
|
Daca vei scrie codul conform standardelor acceptate in programare uneori vei fi ineficient.
Nu am participat la vreun concurs, asa ca nu-mi pot da cu parerea, dar: daca concursul este despre algoritmi si este analizata altceva in afara complexitatii algoritmului, atunci ceva nu-i in regula. Una e sa folosesti un ciclu pentru a calcula suma primelor 100 de numere si alta e sa folosesti formula lui Gauss. In primul caz poti folosi orice artificiu de programare, ca nu vei ajunge la performantele formulei. Nu pot fi de acord cu: "scrie-l oricum, numai sa fie rapid". Aplicatiile reale sunt mari si astfel de "solutii" duc la cod greu de intretinut/inteles si in final la aplicatii ratate. Viteza nu trebuie sa vina din artificii de programare, ci din algoritm. Artificiile de programare adauga un plus de viteza si ininteligibilitate, de cele mai multe ori. Ce ma nemultumeste total este tendinta profeorilor de a lucra cu mijloace invechite. Angajatorii nu asta asteapta. Doar un exemplu: iostream.h in loc de iostream, asa cum prevede standardul curent.
|
|
|
|
|
21
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Memorie/complexitate
|
: Februarie 17, 2013, 16:44:27
|
|
Memoria e impartita in mai multe zone. De interes, in general, este stiva (stack) si free-store (heap).
Stiva este bucata de memorie in care alocarea se face pe principiul LIFO (last-in-first-out). Poti privi stiva ca un teanc de cutii inalt cat o camera (dimensiunea maxima); cand ai nevoie de o variabila locala (automata) iei ultima cutie, o stivuiesti alaturi si tot asa cu urmatoarele variabile. La iesirea din blocul de executie cutiile sunt puse, automat, inapoi in stiva initiala in ordine inverse (daca ai lua prima cutie, stiva s-ar darma). Alocarea variabilelor din stiva este foarte rapida (trebuie doar sa iei cutia urmatoare; nu cauti). int fun() { int i; // i este alocata for ( int j = 0 /* j este alocata */; j < 10; ++j ) { //… } // j este dealocata // ... } // i este dealocata
Memoria dinamica (heap sau free store) este zona de memorie din care alocare/dealocarea se face prin intermediul unui manager (new/delete). Este ca un raft in care ai cutii goale. Cand ai nevoie de o variabila, o ceri managerului (new) iar managerul cauta o cutie goala de dimensiunea ceruta. Cautarea ia mai mult timp decat in cazul stivei, dar heap-ul este mult mai mare decat stiva. Existenta variabilei nu se incheie in mod automat: daca nu mai ai nevoie de ea, trebuie s-o pui inapoi in heap (delete).
Variabilele globale nu sunt alocate pe stiva sau heap; este folosita o zona de memorie dedicata. In c++ utilizarea variabilelor globale este descurajata.
In privinta vitezei, cred ca ar trebui sa te preocupe corectitudinea implementarii, iar daca viteza este alta decat cea asteptata, abia atunci sa-ti pui problema optimizarilor.
Succes.
|
|
|
|
|
22
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: problema .campion
|
: Februarie 15, 2013, 21:16:00
|
Incearca sa declari vectorii mari in afara mainului (pe heap ai mai mult decat pe stiva)
Inainte de a muta declaratia variabilelor, estimeaza spatiul necesar: probabil ca 50000 este mai mult decat ai nevoie. Variabilele globale (cele declarate in afara functiei main) sunt alocate intr-un alt segment de memorie, nu pe heap. //... int g_i; // variabila globala //... int main() { int i; // variabila locala int* pi = new int; // pi este locala dar indica catre o zona de memorie alocata din heap *pi = 10; // memoria de pe heap va contine 10 delete pi; // elibereaza memoria alocata return 0; }
|
|
|
|
|
23
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: problema .campion
|
: Februarie 15, 2013, 20:17:37
|
|
Nu am studiat problema pe care incearca s-o rezolve aplicatia. Am cateva observatii legate de implementare: - De ce vectorii s si sum trebuie sa fie atat de mari? Stiva, probabil ca nu este foarte multumita. Nu programez sub Linux, dar probabil ca mesajul de eroare inseamna ca ai depasit dimensiunea maxima a stivei. - De ce fstream si nu ifstream si ofstream? - Deschiderea cu succes a unui fisier trebuie confirmata: std::ifstream is( "tren1.in" ); if ( ! is ) return -1; // eroare la deschidere - Este indicat ca variabilele locale sa fie declarate pe masura ce sunt folosite. De exemplu, nu are rost sa declari i la inceputul functiei daca este folosit doar in for. Mai corect ar fi: for ( int i = 0; i < n; ++ i ) - Functia main trebuie sa intoarca o valoare.
Succes.
|
|
|
|
|
24
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Librarie <vector>
|
: Februarie 15, 2013, 16:16:51
|
|
Exemplul 2 emuleaza exemplul 1, ca sa scoata in evidenta diferentele intre cele doua abordari.
s este lungimea curenta a vectorului, chiar daca prin declaratia v[VMAX] se aloca 10 elemente. Folosirea oricarui index in afara domeniului [0, s-1] este eronata.
Lungimea fizica a vectorului v[VMAX] este VMAX (chiar daca s capata valoarea VMAX + 10, de exemplu). Lungimea vectorului std::vector< int > v poate fi ajustata dinamic: poate fi zero, 10 sau cat decizi in momentul in care-l folosesti, spre deosebire de abordarea statica in care lungimea nu poate depasi VMAX.
|
|
|
|
|
25
|
infoarena - concursuri, probleme, evaluator, articole / Informatica / Răspuns: Librarie <vector>
|
: Februarie 15, 2013, 14:45:38
|
De ce e eroare logica v[1] = 1? int v[10] ar insemna ca indexul maxim e 9, ok.
VMAX (10) este dimensiunea vectorului static (indexul-fizic corect este de la 0 la 9). Din tot vectorul, exemplul foloseste doar primele s elemente. La acel moment s este 1, deci domeniul valid de indecsi-logici este de la 0 la 0 (de la 1 pina la 9 sunt valori ce nu sunt intializate sau nu mai sunt valide in acel punct). Programul nu o sa "crape" (in jargon) dar e posibil sa se comporte anormal, si se poate termina anormal din cauze indirecte. Nu o sa crape in mod direct pentru ca locatia in care scrii este valida (asa cum ai observat, lungimea-fizica a vectorului este 10 iar indexul 1 este in domeniu). Daca indexul este in afara domeniului-fizic (0-9) atunci scrierea poate avea loc intr-o locatie care nu-i pe placul compilatorului si aplicatia poate crapa fara vreun avertisment. In aplicatiile comerciale vectorii statici sunt rar utilizati. De cele mai multe ori dimensiunile depind de datele introduse de utilizator, asadar ai nevoie de un vector cu lungime ajustabila dinamic.
|
|
|
|
|