#ifndef RIGA_H_
#define RIGA_H_

#include <string>
#include <vector>
using namespace std;

class Riga : public vector<double>
{
public:
    Riga();
	Riga(const vector<double>& elementi);
};

#endif /*RIGA_H_*/

----

#include "Riga.h"

Riga::Riga()
{
}

Riga::Riga(const vector<double>& elementi)
{
    for(int i = 0; i < elementi.size(); i++)
        push_back(elementi[i]);
}


----

#ifndef MATRICE_H
#define MATRICE_H

#include "Riga.h"
#include <cstdlib>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

/* 
Questa classe modella una MATRICE le cui righe sono modellate tramite la
classe Riga definita nel file Riga.h .


Si richiede di implementare nel file Matrice.cpp
tutti i metodi di questa classe ad eccezione del costruttore
(la cui implementazione e' data e non puo' essere modificata).
*/
class Matrice // questa riga e' corretta NON MODIFICARE
{

private:
	/* Le righe della MATRICE sono memorizzate in un vettore,
	 * in questo modo sono numerate naturalmente utilizzando
	 * la posizione dell'oggetto Riga all'interno del vettore
	 */
	vector<Riga> righe;
	
public:
    /*
    Calcola la posizione della riga che ha il minimo modulo fra i moduli di tutte le righe della matrice
    (se piu' righe hanno modulo minimo, il metodo deve restituire la posizione della prima di queste righe).
    Il modulo di una riga e' definito come la radice quadrata della somma dei quadrati dei suoi elementi.
    Ad esempio, il modulo della riga [1, 2, 3] è sqrt(1*1 + 2*2 + 3*3).
    Nota che la funzione sqrt() calcola la radice quadrata di un numero ed e' gia' inclusa nella libreria cmath.
    
    Se la matrice e' vuota, il metodo ritorna -1.
    */
    int rigaConModuloMinimo();

    /*
    Calcola la posizione della colonna che ha il secondo minimo modulo fra i moduli di tutte le colonne della matrice
    (se piu' colonne hanno modulo uguale al secondo minimo, il metodo deve restituire la posizione della prima di queste colonne).
    Il modulo di una colonna e' definito come la radice quadrata della somma dei quadrati dei suoi elementi.
    Ad esempio, per la matrice

        [11, 5, 3]
        [22, 3, 3]
        [33, 6, 3]

    il modulo della seconda colonna è sqrt(5*5 + 3*3 + 6*6), che e' il secondo minimo fra i moduli delle colonne della matrice.
    Quindi, in questo caso, il metodo restituirebbe 1 (posizione della seconda colonna).
    Nota che la funzione sqrt() calcola la radice quadrata di un numero ed e' gia' inclusa nella libreria cmath.
    
    Se la matrice e' vuota, il metodo ritorna -1.
    */    
    int colonnaConModuloSecondoMinimo();


    /*
    Questo metodo restituisce la matrice trasposta.
    La matrice trasposta si ottiene trasformando ogni riga i nella colonna i.
    Ad esempio, la trasposta della matrice

        [1, 5, 3]
        [2, 3, 3]
        [3, 6, 3]

    e'

        [1, 2, 3]
        [5, 3, 6]
        [3, 3, 3]

    */    
    Matrice trasponi();

    /*
    Dato un intero b, questo metodo restituisce la differenza fra:
    - la somma dei numeri che si trovano sul bordo di taglia b, e 
    - la somma dei numeri che si trovano all'interno del bordo di taglia b.
    Ad esempio, per la seguente matrice:

        [1, 2, 3, 4]
        [5, 3, 6, 5]
        [3, 3, 3, 6]

    se b=1, il bordo e':

        [1, 2, 3, 4]
        [5,       5]
        [3, 3, 3, 6]

    mentre l'interno del bordo e':

        [          ]
        [   3, 6   ]
        [          ]

    Quindi, in questo caso, il metodo calcola (1+2+3+4+5+6+3+3+3+5) - (3+6).

    Nota: se b e' maggiore della metà del numero di righe o di colonne, 
    allora il risultato e' pari alla somma dei numeri di tutta la matrice.
    */    
    double sommaInternoMenoBordo(unsigned b);

    /*
    Dato un intero b, sia N1 la differenza fra:
    - la somma dei numeri che si trovano sul bordo di taglia b, e 
    - la somma dei numeri che si trovano all'interno del bordo di taglia b.

    Sia N2 la riga della matrice avente minimo modulo.
    Sia N3 la colonna della matrice trasposta avente secondo minimo modulo.

    Il metodo ritorna true se N1+N2+N3 >= 18.
    False altrimenti.
    */    
    bool metodoStraordinario(unsigned b);
        
	inline vector<Riga>& getContent();
	inline void aggiungiRiga(Riga r);
};

vector<Riga>& Matrice::getContent()
{
    return righe;
}

void Matrice::aggiungiRiga(Riga r)
{
    righe.push_back(r);
}

#endif

----

#include "Matrice.h"

static double moduloRiga(Riga r)
{
    double somma = 0.0;
    for(int j = 0; j < r.size(); j++)
        somma += r[j] * r[j];
    return sqrt(somma);
}

int Matrice::rigaConModuloMinimo()
{
    if(righe.size() == 0)
        return -1;
        
    double min = moduloRiga(righe[0]);
    int pos = 0;
    
    for(int i = 1; i < righe.size(); i++)
    {
        double tmp = moduloRiga(righe[i]);
        if(tmp < min)
        {
            min = tmp;
            pos = i;
        }
    }
    
    return pos;
}

int Matrice::colonnaConModuloSecondoMinimo()
{
    if(righe.size() == 0)
        return -1;

    Matrice t = trasponi();
    int min = t.rigaConModuloMinimo();
    Riga r = t.getContent()[min];
    t.getContent().erase(t.getContent().begin()+min);
    int res = t.rigaConModuloMinimo();
    return res < min ? res : res + 1;
}
    
/* ALTERNATIVA
static double moduloColonna(Matrice& m, int c)
{
    double somma = 0.0;
    for(int j = 0; j < m.getContent().size(); j++)
        somma += m.getContent()[j][c] * m.getContent()[j][c];
    return sqrt(somma);
}

int Matrice::colonnaConModuloSecondoMinimo()
{
    if(righe.size() == 0)
        return -1;

    double min = moduloColonna(*this, 0);
    int pos = 0;
    double submin = moduloColonna(*this, 1);
    int possub = 1;
    if(submin < min)
    {
        double tmp = min;
        min = submin;
        submin = tmp;
        int t = pos;
        pos = possub;
        possub = t;
    }
    
    for(int i = 2; i < righe[0].size(); i++)
    {
        double tmp = moduloColonna(*this, i);
        if(tmp < min)
        {
            submin = min;
            possub = pos;
            min = tmp;
            pos = i;
        }
        else if(tmp < submin)
        {
            submin = tmp;
            possub = i;
        }
    }
    
    return possub;
}
*/

Matrice Matrice::trasponi()
{
    Matrice trasposta;
    
    if(!righe.empty())
    {
        for(int c = 0; c < righe[0].size(); c++)
        {
            vector<double> v;
            for(int r = 0; r < righe.size(); r++)
                v.push_back(righe[r][c]);
            trasposta.aggiungiRiga(Riga(v));
        }
    }
    
    return trasposta;
}

double Matrice::sommaInternoMenoBordo(unsigned b)
{
    double somma = 0;
    
    for(int i = 0; i < righe.size(); i++)
    {
        for(int j = 0; j < righe[i].size(); j++)
        {
            if(b <= i && i < righe.size() - b && b <= j && j < righe[i].size() - b)
                somma -= righe[i][j];
            else
                somma += righe[i][j];
        }
    }
    
    return somma;
}

bool Matrice::metodoStraordinario(unsigned b)
{
    double N1 = sommaInternoMenoBordo(b);
    int N2 = rigaConModuloMinimo();
    int N3 = trasponi().colonnaConModuloSecondoMinimo();
    return N1 + N2 + N3 >= 18;
}

