Programma con array bidimensionali!!!!
salve a tutti gente, avrei bisogno di sapere come si risolve questo esercizio
è un esercizio d'esame
ecco il testo:
Scrivere una funzione C++ che dato un array a due dimensioni N x N di interi a, un intero n>=1 ed un intero k, restituisce TRUE se e solo se in ogni colonna esistono n coppie distinte di elementi la cui somma sia pari a k.
è un esercizio d'esame
ecco il testo:
Scrivere una funzione C++ che dato un array a due dimensioni N x N di interi a, un intero n>=1 ed un intero k, restituisce TRUE se e solo se in ogni colonna esistono n coppie distinte di elementi la cui somma sia pari a k.
Risposte
@apatriarca
ma a me non compila e non stampa nulla
perchè
ecco il programma completo con modifiche da te consigliate apportate
ma a me non compila e non stampa nulla
perchè
ecco il programma completo con modifiche da te consigliate apportate
#include<iostream> using namespace std; const int N=5; bool verifica_coppia(int [N][N], int , int, int); bool condizione(int [N][N], int, int); int main() { int k,n; int a[N][N]={{3,1,2,2,3},{3,1,2,2,3},{3,1,2,2,3},{3,1,2,2,3},{3,1,2,2,3}}; cout<<"Inserisci un numero(somma degli elementi della coppia "; cin>>k; cout<<"Inserisci un numero(numero di elementi della coppia) "; cin>>n; cout<<condizione(a,k,n); return 0; } bool verifica_coppia(int y[N][N], int b,int numero,int c) { int i,j; bool trovata=false; int cont=0; bool visitato[N]; for(i=0;i<N;i++){ visitato[i]=false; } i=0; while(i<N && !trovata) { if(visitato[i])continue; visitato[i]=true; j=i+1; int b=0; while(j<N) { if(y[i][c]==y[j][c]) { visitato[j]=true; } if((y[i][c]+y[j][c])==b) { b=1; } j++; } cont+=b; i++; if(cont==numero) trovata=true; } return trovata; } bool condizione(int x[N][N],int r,int val) { int s=0; bool condition=true; while(s<N && condition) { condition=verifica_coppia(x,r,val,s); if(condition) { s++; cout<<"La condizione è verificata"<<endl; } else { cout<<"La condizione NON è verificata"<<endl; } } return condition; }
allora
@apatriarca
hai capito dove sta il problema?
@apatriarca
hai capito dove sta il problema?
E tu hai provato a capirlo in qualche modo? Non ho avuto il tempo/voglia di mettermi a testare il codice, fare il debug..
io ho apportato la modifica che tu mi hai detto
ora visto che il compilatore non dà errori ma non esegue(la schermata resta nera e mi chiede solamente di inserire i valori)
ti chiedevo di darmi un ultima mano visto che ne ho davvero bisogno
grazie mille aspetto una tua risposta
ora visto che il compilatore non dà errori ma non esegue(la schermata resta nera e mi chiede solamente di inserire i valori)
ti chiedevo di darmi un ultima mano visto che ne ho davvero bisogno
grazie mille aspetto una tua risposta
Ci darò un'occhiata, ma tu ci hai capito qualcosa del codice o stai solo seguendo le nostre indicazioni alla cieca?
sisi ho capito e vi ringrazio
sarò ancora più sicuro se funziona perfettamente
grazie allora spero di avere tue notizie al più presto
sarò ancora più sicuro se funziona perfettamente
grazie allora spero di avere tue notizie al più presto
Ho notato che hai cambiato alcune cose nel codice che avevo postato ma che non hai fatto alcune delle correzioni che mi sembra Umby avesse suggerito. Per cui direi che è meglio "ripartire da zero" che rimettere a posto il casino che si è creato in queste 5 pagine. Ci sono prima di tutto un paio di commenti "di stile" che vorrei fare:
1. In C++ non è necessario dichiarare tutte le variabili all'inizio del loro blocco di esistenza ma possono essere definite subito prima del loro uso. In questo modo è più chiaro il loro scopo, è spesso possibile renderle costanti, ci sono meno rischi di commettere errori perché la variabile è accessibile in un numero più limitato di codice e perché è più difficile avere una variabile non inizializzata. Credo che ci siano insomma tantissimi motivi per non seguire la vecchia abitudine proveniente da C (dopotutto non è presente in nessun altro linguaggio e nell'ultimo sfortunato standard del C è stato rimossa la limitazione). Siccome preferisco definire le variabili più tardi possibile nel codice, questa sarà una prima differenza che noterai rispetto al tuo vecchio codice.
2. Per aiutarmi a seguire il flusso del programma in programmi così piccoli e limitati preferisco usare i nomi in modo consistente anche passando da una funzione all'altra. Se ho quindi una variabile n che viene passata in giro per tutto il programma la chiamerò n in tutte le funzioni. È probabile che a te non piaccia perché credo che tu li abbia cambiati tutti i nomi dei parametri dalla mia alla tua versione. Ma siccome lo preferisco lo scriverò a modo mio. Sentiti pure libero di cambiare i nomi nel tuo codice.
3. Preferisco i cicli for ai cicli while quando si usa un contatore. Siccome hai usato un ciclo for nel codice immagino che tu ne conosca il significato. Per cui non ci saranno cicli while.
4. Siccome mi hai invece detto di non sapere il significato di continue (e immagino anche break) eviterò di usarli nel codice.
5. Non mi piace usare using namespace e preferisco indicare direttamente std:: tutte le volte.. Immagino mi crederai pazzo ma c'è un motivo per cui hanno creato i namespace.
Passiamo allora al problema. Per prima cosa riporto nuovamente il testo dell'esercizio, con le "aggiunte" scoperte durante la discussione.
Sul main non c'è molto da discutere per cui lo riporto con poche ininfluenti modifiche. La più importante riguarda la definizione della matrice. Il testo parla chiaramente di colonne e in base a quello che ritenessi dovesse essere la risposta sbagliata con il tuo codice ho concluso che non sai che le matrici in C++ vengono dichiarate PER RIGA!!! Per cui ti ho trasposto la matrice in modo che per n=2 e k=5 la risposta debba essere positiva.
Come promesso i parametri di condizione cambiano nome in a, k ed n. Anche in questo caso il codice va bene e lo incollo con qualche piccola leggera modifica principalmente stilistica. La modifica più importante è stata quella di eliminare condition uscendo dalla funzione alla prima colonna falsa (e quindi potendo supporre di restituire true al di fuori del ciclo perché ogni colonna è stata testata con successo). Ho dovuto anche inserire la funzione direttamente nella selezione.
Passiamo allora alla funzione che genera problemi. Fino a questo punto non si possono essere cicli infiniti (sembra proprio che il tuo codice giri indefinitamente in un ciclo infinito). Ripeto qui l'algoritmo al quale si era arrivati in precedenza nella discussione:
1. Per ogni elemento della colonna i-esima verifico prima di tutto se è necessario analizzarlo. Se infatti si è già verificato se l'elemento da origine ad una qualche coppia, posso saltarlo. Se l'elemento non è stato ancora visitato, lo segno come visitato.
2. Per ogni elemento della colonna successivo all'elemento che sto analizzando, controllo se sia uguale a questo elemento (in questo caso lo segno come già visitato) oppure uguale a k meno l'elemento e in questo caso ho trovato una coppia e incremento il numero di coppie trovate.
3. Passo quindi all'elemento successivo fino alla fine della colonna.
4. Una volta che ho contato il numero di coppie disgiunte la cui somma è uguale a k lo confronto con n e se è uguale restituisco true, se diverso false.
Il codice completo funzionante è quindi il seguente. Fammi sapere se non capisci qualcosa.
P.S. Non ho esattamente idea di cosa causasse il ciclo infinito nel vecchio codice. Ma l'algoritmo sbagliato (in cui il conteggio delle coppie avveniva nel ciclo ad esempio) contribuiva a rendere certamente tutto inutilmente molto più complicato. Probabilmente veniva per sbaglio modificato un qualche ciclo o c'era una condizione sbagliata da qualche parte. Se vuoi proverò a darci un occhiata più attenta. In ogni caso la funzione andava riscritta per aggiustare l'algoritmo.
1. In C++ non è necessario dichiarare tutte le variabili all'inizio del loro blocco di esistenza ma possono essere definite subito prima del loro uso. In questo modo è più chiaro il loro scopo, è spesso possibile renderle costanti, ci sono meno rischi di commettere errori perché la variabile è accessibile in un numero più limitato di codice e perché è più difficile avere una variabile non inizializzata. Credo che ci siano insomma tantissimi motivi per non seguire la vecchia abitudine proveniente da C (dopotutto non è presente in nessun altro linguaggio e nell'ultimo sfortunato standard del C è stato rimossa la limitazione). Siccome preferisco definire le variabili più tardi possibile nel codice, questa sarà una prima differenza che noterai rispetto al tuo vecchio codice.
2. Per aiutarmi a seguire il flusso del programma in programmi così piccoli e limitati preferisco usare i nomi in modo consistente anche passando da una funzione all'altra. Se ho quindi una variabile n che viene passata in giro per tutto il programma la chiamerò n in tutte le funzioni. È probabile che a te non piaccia perché credo che tu li abbia cambiati tutti i nomi dei parametri dalla mia alla tua versione. Ma siccome lo preferisco lo scriverò a modo mio. Sentiti pure libero di cambiare i nomi nel tuo codice.
3. Preferisco i cicli for ai cicli while quando si usa un contatore. Siccome hai usato un ciclo for nel codice immagino che tu ne conosca il significato. Per cui non ci saranno cicli while.
4. Siccome mi hai invece detto di non sapere il significato di continue (e immagino anche break) eviterò di usarli nel codice.
5. Non mi piace usare using namespace e preferisco indicare direttamente std:: tutte le volte.. Immagino mi crederai pazzo ma c'è un motivo per cui hanno creato i namespace.
Passiamo allora al problema. Per prima cosa riporto nuovamente il testo dell'esercizio, con le "aggiunte" scoperte durante la discussione.
Scrivere una funzione C++ che dato un array a due dimensioni N x N di interi a, un intero n>=1 ed un intero k, restituisce TRUE se e solo se in ogni colonna esistono esattamente n coppie distinte di elementi la cui somma sia pari a k (considerando come disgiunte le coppie che si ottengono riordinando i termini).
Sul main non c'è molto da discutere per cui lo riporto con poche ininfluenti modifiche. La più importante riguarda la definizione della matrice. Il testo parla chiaramente di colonne e in base a quello che ritenessi dovesse essere la risposta sbagliata con il tuo codice ho concluso che non sai che le matrici in C++ vengono dichiarate PER RIGA!!! Per cui ti ho trasposto la matrice in modo che per n=2 e k=5 la risposta debba essere positiva.
#include<iostream> const int N = 5; bool verifica_coppia(int [N][N], int , int, int); bool condizione(int [N][N], int, int); int main() { std::cout << "Inserisci il numero n di coppie disgiunte: "; int n = 0; std::cin >> n; std::cout << "Inserisci la somma k degli elementi della coppia: "; int k = 0; std::cin >> k; int a[N][N] = {{3,3,3,3,3}, {1,1,1,1,1}, {2,2,2,2,2}, {2,2,2,2,2}, {3,3,3,3,3}}; std::cout << "Il risultato e' " << condizione(a, k, n) << std::endl; return 0; }
Come promesso i parametri di condizione cambiano nome in a, k ed n. Anche in questo caso il codice va bene e lo incollo con qualche piccola leggera modifica principalmente stilistica. La modifica più importante è stata quella di eliminare condition uscendo dalla funzione alla prima colonna falsa (e quindi potendo supporre di restituire true al di fuori del ciclo perché ogni colonna è stata testata con successo). Ho dovuto anche inserire la funzione direttamente nella selezione.
bool condizione(int a[N][N], int k, int n) { for (int i = 0; i < N; ++i) { if (verifica_coppia(a, k, n, i)) { std::cout << "La condizione e' verificata per la colonna " << i << std::endl; } else { std::cout << "La condizione NON e' verificata per la colonna " << i << std::endl; return false; } } return true; }
Passiamo allora alla funzione che genera problemi. Fino a questo punto non si possono essere cicli infiniti (sembra proprio che il tuo codice giri indefinitamente in un ciclo infinito). Ripeto qui l'algoritmo al quale si era arrivati in precedenza nella discussione:
1. Per ogni elemento della colonna i-esima verifico prima di tutto se è necessario analizzarlo. Se infatti si è già verificato se l'elemento da origine ad una qualche coppia, posso saltarlo. Se l'elemento non è stato ancora visitato, lo segno come visitato.
2. Per ogni elemento della colonna successivo all'elemento che sto analizzando, controllo se sia uguale a questo elemento (in questo caso lo segno come già visitato) oppure uguale a k meno l'elemento e in questo caso ho trovato una coppia e incremento il numero di coppie trovate.
3. Passo quindi all'elemento successivo fino alla fine della colonna.
4. Una volta che ho contato il numero di coppie disgiunte la cui somma è uguale a k lo confronto con n e se è uguale restituisco true, se diverso false.
bool verifica_coppia(int a[N][N], int k, int n, int i) { bool visitato[N]; for(int j = 0; j < N; ++j) { visitato[j] = false; } int coppie = 0; for (int j = 0; j < N; ++j) { if (!visitato[j]) { visitato[j] = true; int v = a[j][i]; int k_minus_v = k - v; int b = 0; for (int k = j+1; k < N; ++k) { if (a[k][i] == v) { visitato[k] = true; } if (a[k][i] == k_minus_v) { b = 1; } } coppie += b; } } return coppie == n; }
Il codice completo funzionante è quindi il seguente. Fammi sapere se non capisci qualcosa.
#include<iostream> const int N = 5; bool verifica_coppia(int [N][N], int , int, int); bool condizione(int [N][N], int, int); int main() { std::cout << "Inserisci il numero n di coppie disgiunte: "; int n = 0; std::cin >> n; std::cout << "Inserisci la somma k degli elementi della coppia: "; int k = 0; std::cin >> k; int a[N][N] = {{3,3,3,3,3}, {1,1,1,1,1}, {2,2,2,2,2}, {2,2,2,2,2}, {3,3,3,3,3}}; std::cout << "Il risultato e' " << condizione(a, k, n) << std::endl; return 0; } bool verifica_coppia(int a[N][N], int k, int n, int i) { bool visitato[N]; for(int j = 0; j < N; ++j) { visitato[j] = false; } int coppie = 0; for (int j = 0; j < N; ++j) { if (!visitato[j]) { visitato[j] = true; int v = a[j][i]; int k_minus_v = k - v; int b = 0; for (int k = j+1; k < N; ++k) { if (a[k][i] == v) { visitato[k] = true; } if (a[k][i] == k_minus_v) { b = 1; } } coppie += b; } } return coppie == n; } bool condizione(int a[N][N], int k, int n) { for (int i = 0; i < N; ++i) { if (verifica_coppia(a, k, n, i)) { std::cout << "La condizione e' verificata per la colonna " << i << std::endl; } else { std::cout << "La condizione NON e' verificata per la colonna " << i << std::endl; return false; } } return true; }
P.S. Non ho esattamente idea di cosa causasse il ciclo infinito nel vecchio codice. Ma l'algoritmo sbagliato (in cui il conteggio delle coppie avveniva nel ciclo ad esempio) contribuiva a rendere certamente tutto inutilmente molto più complicato. Probabilmente veniva per sbaglio modificato un qualche ciclo o c'era una condizione sbagliata da qualche parte. Se vuoi proverò a darci un occhiata più attenta. In ogni caso la funzione andava riscritta per aggiustare l'algoritmo.
allora io ho provato il programma ma non funziona nei casi che ti avevo messo negli esempi
se la colonna dovesse essere
il risultato dovrebbe essere true per tutte le colonne(ponendole tutte uguali ovviamente)
invece dice che la condizione non è verificata
ma esistobo( per n=2 e k=5)
due coppie distinte
la cui somma dà 5=k
se la colonna dovesse essere
{3,1,2,2,3}
il risultato dovrebbe essere true per tutte le colonne(ponendole tutte uguali ovviamente)
invece dice che la condizione non è verificata
ma esistobo( per n=2 e k=5)
due coppie distinte
(3,2) e (2,3)
la cui somma dà 5=k
{3,1,2,2,3}
È una RIGA!!! Le matrici in C++ sono per riga e non per colonna. Questo significa che la matrice che hai scritto ha tutte le colonne con lo stesso elemento e quindi non può avere più di una coppia (se ne ha una). Di certo il risultato NON è quello che ti aspetti, ma il problema a questo punto non è nel codice ma nella tua comprensione del C++ e del modo in cui le matrici vengono inizializzate.
scusa ho soltanto un' altra domanda
ma se nn volessi usare l' std visto che non l'ho studiato
e usare il using namespace std cosa devo fare mi basta sostituire e funziona lo stesso ?
ma se nn volessi usare l' std visto che non l'ho studiato
e usare il using namespace std cosa devo fare mi basta sostituire e funziona lo stesso ?
"using namespace std" serve esclusivamente per evitare di scrivere std:: tutte le volte. Devi quindi semplicemente cancellare tutti gli std:: e aggiungere quella linea di codice.
ok capito
un altro dubbio risolto
grazie mille
un altro dubbio risolto
grazie mille
@apatriarca
scusa una cosa non ho capito bene , rivedendo ora il codice
ma il k che hai usato in questo ciclo è lo stesso passato nella funzione?
scusa una cosa non ho capito bene , rivedendo ora il codice
for (int k = j+1; k < N; ++k) { if (a[k][i] == v) { visitato[k] = true; }
ma il k che hai usato in questo ciclo è lo stesso passato nella funzione?

for (int r = j+1; r < N; ++r) { if (a[r][i] == v) { visitato[r] = true; } if (a[r][i] == k_minus_v) { b = 1; } }
ok ok grazie era solo un piccolo dubbio ma avevo già capito
tu mi hai dato la conferma
ti ringrazio infinitamente di nuovo
tu mi hai dato la conferma
ti ringrazio infinitamente di nuovo