[C++] - problem so spracovanim vyrazu

Programovacie jazyky, rady, poradňa...
javo
Medium Expert
Medium Expert
Používateľov profilový obrázok
Príspevky: 89
Registrovaný: 15 sep 2006, 21:30
Kontaktovať používateľa:

[C++] - problem so spracovanim vyrazu

Príspevok od používateľa javo »

Zdravim,

Poslednu dobu sa snazim riesit priklady na liahen.ksp.sk, narazil som vsak na priklad s ktorym si neviem dat rady, vsetky mozne vstupy ktore testujem u mna na pc mi idu, trapim sa s tym uz hodne dlho tak som sa rozhodol pre poslednu moznost - poradit sa s Vami na fore
Bol by som moc rad keby ste mi pomohli zistit ci mam v programe chybu, a kde, dakujem

tu je zadanie a moj kod

Kód: Vybrať všetko

Vstup

V prvom riadku vstupu je jedno celé číslo N (1 ≤ N ≤ 100), udávajúce počet riadkov Kubkovho výpočtu.

Nasleduje N riadkov. Každý z nich obsahuje zátvorky z jedného riadku Kubkovho výpočtu. Presnejšie, každý riadok obsahuje jeden reťazec tvorený aspoň 1 a najviac 100 znakmi ()[]{}.
Výstup

Tvoj program by mal vypísať N riadkov – pre každý výraz zo vstupu vypíš ANO alebo NIE, podľa toho, či je dobre uzátvorkovaný. 
moj kod

Kód: Vybrať všetko

#include <stack>
#include <iostream>
#include <string>
using namespace std;
int i;
char pole[150];

char reverse(char c){
if(c == ']')return '[';
if(c == ')')return '(';
if(c == '}')return '{';
}

int main() {
scanf("%i",&i);
while(i--)
{

	scanf("%s",&pole);
	int j;
	stack<char> S;
	for(j=0;j<strlen(pole);j++){
	if(S.empty())
		{
		S.push(pole[j]);
		}else{
			if(S.top()==reverse(pole[j])) S.pop(); else S.push(pole[j]);
		}
	}
	cout << (S.empty() ? "ANO" : "NIE") << endl;
	
}
  return 0;
}
audiotrack
VIP
VIP
Používateľov profilový obrázok
Príspevky: 25958
Registrovaný: 09 sep 2005, 18:39
Kontaktovať používateľa:

Príspevok od používateľa audiotrack »

chyba je v tvojej funkcii reverse(), v ktorej máš ošetrené iba 3 možnosti ktoré sú zdanlivo postačujúce, no keď si uvedomiš ako tvoj algoritmus funguje, zistíš že tomu tak nie je. Ide o to, že meni zatvárajúcu zátvorku na otvárajúcu. A teda ak mám výraz [] tak tú druhú premení na [ a porovná s predchádzajúcou. Nastane zhoda, všetko šlape. No čo ak dám vstup [[. Druhú zátvorku nepremení lebo nie je v podmienke funkcie reverse a vráti ju teda nezmenenú. Znova sa obe zátvorky zhodujú tak zase vráti áno. Môžeš si skúsiť že pre lubovolný vstup ktorý párny počet neuzatvorených zasebou idúcich otváracích zátvoriek ti vráti ANO, napríklad: ((((((((( alebo ((((()()()() alebo ()()(([]{{() ...

//edit: dokonca keď na to tak pozerám, vôbec by nemal vyhodnoitiť ako správne uzátvorkovaný výraz aj taký, kde nie sú zátvorky ale nepovelené znaky (samozrejme zase rovnaký párny počet), napríklad vstup aa by tiež napísalo ANO. Asi by si mal aj robiť kontrolu či skutočne ide o zátvorku a nespoliehať sa na to že budú vstupy také ako píše zadanie.
javo
Medium Expert
Medium Expert
Používateľov profilový obrázok
Príspevky: 89
Registrovaný: 15 sep 2006, 21:30
Kontaktovať používateľa:

Príspevok od používateľa javo »

audiotrack napísal:chyba je v tvojej funkcii reverse(), v ktorej máš ošetrené iba 3 možnosti ktoré sú zdanlivo postačujúce, no keď si uvedomiš ako tvoj algoritmus funguje, zistíš že tomu tak nie je. Ide o to, že meni zatvárajúcu zátvorku na otvárajúcu. A teda ak mám výraz [] tak tú druhú premení na [ a porovná s predchádzajúcou. Nastane zhoda, všetko šlape. No čo ak dám vstup [[. Druhú zátvorku nepremení lebo nie je v podmienke funkcie reverse a vráti ju teda nezmenenú. Znova sa obe zátvorky zhodujú tak zase vráti áno. Môžeš si skúsiť že pre lubovolný vstup ktorý párny počet neuzatvorených zasebou idúcich otváracích zátvoriek ti vráti ANO, napríklad: ((((((((( alebo ((((()()()() alebo ()()(([]{{() ...

//edit: dokonca keď na to tak pozerám, vôbec by nemal vyhodnoitiť ako správne uzátvorkovaný výraz aj taký, kde nie sú zátvorky ale nepovelené znaky (samozrejme zase rovnaký párny počet na začiatku), napríklad vstup aa by tiež napísalo ANO. Asi by si mal aj robiť kontrolu či skutočne ide o zátvorku a nespoliehať sa na to že budú vstupy také ako píše zadanie.
no neviem, vstupy ktore opisujes mi vyhodnoti ako NIE, skusil som tiez zadat aa a vyhodnotilo to taky ako NIE,
bolo potrebne editovat funkciu reverse na

Kód: Vybrať všetko

char reverse(char c){
if(c == ']')return '[';else
if(c == ')')return '(';else
if(c == '}')return '{';else return 'f';
}
neuvedomil som si funkcia bude vraciat tu istu hodnotu a teda pokazi cely algoritmus, no prave na toto je dana stranka dobra :) dakujem za pomoc
audiotrack
VIP
VIP
Používateľov profilový obrázok
Príspevky: 25958
Registrovaný: 09 sep 2005, 18:39
Kontaktovať používateľa:

Príspevok od používateľa audiotrack »

to je teda zvláštne, v prílohe máš presne ten zdroják čo si písal. Skús spustiť to exe a zadaj (( ako vstup
Prílohy
javo.rar
(115.09 KiB) 36 stiahnutí
javo
Medium Expert
Medium Expert
Používateľov profilový obrázok
Príspevky: 89
Registrovaný: 15 sep 2006, 21:30
Kontaktovať používateľa:

Príspevok od používateľa javo »

audiotrack napísal:to je teda zvláštne, v prílohe máš presne ten zdroják čo si písal. Skús spustiť to exe a zadaj (( ako vstup
hmm zvlastne, zeby to bolo zavisle na platforme? resp. kompilatore,
ja pouzivam gcc version 4.2.3 (Gentoo 4.2.3 p1.0) a tam to ide ako som pisal
tuti
Light Professional
Light Professional
Používateľov profilový obrázok
Príspevky: 740
Registrovaný: 01 okt 2006, 19:23
Bydlisko: Prievidza

Príspevok od používateľa tuti »

skusim poradit:
funkcia reverse moze byt kludne bez tych else (ked sa nevykona if automaticky sa ta cast preskoci a ide sa na dalsie if) a na zaverecny return by som nedal 'f' ale napr. \0 (moze byt aj 'f' ale predsa len to nie je nejaka hodnota ktora cloveka napadne ako chybova) a hlavne \0 nemoze zadat uzivatel ako vstup

a ako spravit algoritmus aby fungoval spravne a rychlejsie:
1.1) ak nie je co citat a zasobnik prazdny vyraz je dobry
1.2) nacitam znak
2) kontrola ci je zatvorka otvaracia
2.1) je otvaracia -> dam na zasobnik -> goto 1
2.2) je uzatvaracia -> porovnam ci su si navzajom odpovedajuce (samozrejme kontrola ci na zasobniku nieco je)
2.2.1) ak su -> odstranim vrchnu zatvorku zo zasobnika -> goto 1
2.2.2) ak nie su -> ukoncim vyhodnocovanie vyrazu (je na 100% zly)

Kód: Vybrať všetko

#include <stack>
#include <iostream>
#include <string>
using namespace std;

char reverse(char c)
{
	if(c == ']')return '[';
	if(c == ')')return '(';
	if(c == '}')return '{';
	return '\0';
}

bool open(char c) {
	if((c == '[') || (c == '(') || (c == '{')return true;
	return false;
}

bool close(char c) {
	if((c == ']') || (c == ')') || (c == '}')return true;
	return false;
}

int main() 
{
	int i;
	char pole[150]; 
	scanf("%i",&i);
	while(i--) 
	{
   	scanf("%s",&pole);
   	int j;
   	stack<char> S;
   	for(j=0;j<strlen(pole);j++){
   		if(open(pole[j]) {
      		S.push(pole[j]);
      	} else if(close(pole[j]) {
         	if(!S.empty()) {
         		if(S.top()==reverse(pole[j])) {
						S.pop(); 
						break;
					}
				}
				cout << "NIE" << endl;
				break;
      	}
      	else {
				cout << "Neplatny znak" << endl; 
				break;
			}
   	}
   	cout << (S.empty() ? "ANO" : "NIE") << endl;
	}
  return 0;
}
/ doplneny kod...nebol testovany ale mal by ist
chrono
VIP
VIP
Používateľov profilový obrázok
Príspevky: 7127
Registrovaný: 25 dec 2006, 15:17

Príspevok od používateľa chrono »

audiotrack napísal:to je teda zvláštne, v prílohe máš presne ten zdroják čo si písal. Skús spustiť to exe a zadaj (( ako vstup
Ono to súvisí s použitým kompilátorom. Tá funkcia vráti výsledok cez nejaký register a potom sa to porovnáva. Ak sa tá vstupná hodnota pred testom vloží do toho registra, v ktorom sa potom očakáva výsledok, tak sa to bude správať presne ako popisuješ ty.
tuti
Light Professional
Light Professional
Používateľov profilový obrázok
Príspevky: 740
Registrovaný: 01 okt 2006, 19:23
Bydlisko: Prievidza

Príspevok od používateľa tuti »

ono hlavna chyba bola v tom ze funkcia mohla skoncit a nevratit ziadnu hodnotu aj napriek tomu ze ma vratit char. Vlastne sa vrati nedefinova hodnota cize nemozes vediet co tam bude. potom zalezi na prekladaci ci tu hodnotu vynuluje alebo tam budu nejake smeti.

keby si pri prekladany suboru pouzil pre gcc prepinac -Wall tak ti tak napisanu funkciu reverse oznaci za warning a pri pouziti -pedantic dokonca nevytvori samotny program.

to chrono: skor by som cakal ze na zasobniku sa vytvori miesto pre navratovu hodnotu a potom zalezi na kompilatore ci miesto preventivne vymaze alebo nie, kedze sa ocakava ze sa tam bude zapisovat
chrono
VIP
VIP
Používateľov profilový obrázok
Príspevky: 7127
Registrovaný: 25 dec 2006, 15:17

Príspevok od používateľa chrono »

Ak funkcia vracia nejaký jednoduchý dátový typ, tak sa vráti (kvôli rýchlosti) cez register.
Napísať odpoveď