[C] Programma particolare sulle matrici.

giovanta-votailprof
Il testo è:
Scrivere un programma in C che acquisisce una matrice 30 X 20 di numeri interi da tastiera e scrive in un'altra matrice di ugual dimensione, in cui ogni elemento ha come valore la media dei valori degli elementi circostanti.
Per gli elementi di bordo si usino solamente quelli esistenti.

ESEMPIO GRAFICO:

1 2 3 5 -1 4 2
3 4 3 4 -7 5 2
5 2 -7 0 1 -2 1
8 -7 5 7 0 9 1
1 2 3 5 3 4 2

matrice medie:

3.00 2.80 3.60 0.40 2.20 0.20 3.67
2.80 1.50 1.62 -0.38 2.00 0.00 2.00
2.00 1.75 2.25 0.75 2.00 1.50 3.00
0.60 2.38 0.62 1.25 3.38 1.25 2.80
1.00 2.00 2.40 3.60 5.00 3.00 4.67


Sono riuscito a fare la parte di programma relativa ai numeri interni al bordo:
#include<stdio.h>
#define R 30
#define C 20
    int main(){
      int m[R][C],i,j,h,k;
      float n[R][C],m,s=0;
      printf("Inserisci la matrice: ");
      for(i=0;i<R;i++)
        {for(j=0;j<C;j++)
          {scanf("%d",&m[i][j]);}
         }
      for(i=0;i<R;i++)
       {for(j=0;j<C;j++)
         {s=0;
           if(i!=0&&i!=R-1&&j!=0&&j!=C-1)
           {for(h=i-1,k=j-1;h<=i+1,k<=j+1;h++,k++)
             {if(h!=i&&k!=j)
               {s+=m[h][k];}
              }
            }
          m=s/8;
          n[i][j]=m;
          }
         }


Per i bordi esterni però non ho capito se si riesce a fare un codice unico oppure un pezzo di codice diverso per ogni lato...

Risposte
marx1
puoi modificare la tua matrice di partenza mettendo una cornice di zero che non influiranno nella media

apatriarca
@marx: ma la cornice di zero influirebbe sulla media, per fare in modo che non influisca si dovrebbe modificare il numero di valori presi in considerazione. Invece di dividere per 8, si dovrebbe dividere per 5 o 3 rispettivamente su bordo e angoli.

@giovanta: Il codice seguente non fa quello che desideri. Modificando h e k nello stesso ciclo rimangono uguali ad ogni iterazioni e quindi stai in pratica considerando solo i valori sulla diagonale del blocco intorno all'elemento corrente.
for(h=i-1,k=j-1;h<=i+1,k<=j+1;h++,k++) {
    if(h!=i&&k!=j) {
        s+=m[h][k];
    }
} 

Devi scrivere due cicli. Per esempio:
for (h = i-1; h < i +1; ++h) {
    for (k = j-1; k < j+1; ++k) {
        // ...
    }
}

Una soluzione semplice a questo punto potrebbe essere quella di verificare ad ogni iterazione se m[h][k] sta all'interno della matrice e diversi da m[j]. Controlli quindi se h e k sono all'interno dei limiti della matrice e se sono diversi rispettivamente da i e j. Una volta fatto questo rimarrebbe il problema di determinare il numero di elementi che hai considerato per la media, ma per farlo è sufficiente avere un contatore che viene incrementato ogni volta che sommi qualcosa alla somma. Spero sia tutto chiaro.

Umby2
Considerato che un numero ha 8 numeri attorno, eviterei di creare un ciclo complesso per il calcolo delle coordinate.
+1,0
-1,0
0,+1
0,-1
+1,+1
+1,-1
-1,+1
-1,-1
per ognuno dei numeri creati verificherei se rientra o meno nei limiti (1 minore-uguale x minore uguale max)
se rientra lo somma alla media, e sommo il contatore dei numeri validi, se non rientra lo scarto

Riuzaki
io posso dare il mio contributo cercando di dirti un semplice algoritmo che mi è venuto in mente per assegnare ad ogni elemento la somma degli elementi circostanti, una volta che hai la somma è molto facile trovarti la media...lascio a te questo piccolo problemino XD..

 for(int i = 0; i < N; i++)
            for(int j = 0; j < N; j++){
                for(int z = i - 1; z <= i + 1; z++)
                    for (int x = j - 1; x <= j + 1; x++)
                      if((z >= 0 && z < N) && (x >= 0 && x < N)){
                      B[i][j] += A[z][x];
                     }    
                 
                 B[i][j] -= A[i][j];         
           }

apatriarca
Si potrebbe anche calcolare i limiti in anticipo:
int x_min = i-1 > 0 ? i-1 : 0; // max(i-1, 0)
int x_max = i+2 < N ? i+2 : N; // min(i+2, N)
int y_min = j-1 > 0 ? j-1 : 0; // max(j-1, 0)
int y_max = j+2 < M ? j+2 : M; // min(j+2, M)

int sum = -A[i][j], n = -1;

for (int x = x_min; x < x_max; ++x) {
    for (int y = y_min; y < y_max; ++y) {
        sum += A[x][y];
        ++n;
    }
}
B[i][j] = static_cast<float>(sum)/static_cast<float>(n); 

L'uso di funzioni inline per il massimo o minimo semplificherebbe un po' la comprensione del codice. Questa soluzione su alcune piattaforme potrebbe essere più efficiente della versione di Riuzaki per via di istruzioni tipo CMOV su x86 (è però solo una ipotesi non avendo fatto alcun test). Scrivere direttamente tutti i casi non credo sia particolarmente conveniente. Sei infatti costretto a scrivere un if per ogni elemento e la probabilità di sbagliare a scrivere qualcosa è molto alta. Per semplic

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.