PDA

View Full Version : [Vari] Contest 3: La somma


gugoXX
22-07-2008, 01:11
Forza, muoviamo sto clock, sia del cervello che del computer.

Sia data una lista di interi disordinata (vedi fondo del post)

Esempio: 1 13 10 22 5 7 5 3 1 7 3 7

A- Base
Trovare quanti sono gli elementi che sono ripetuti almeno 2 volte. Nell'esempio e' 4 (Ci sono 4 valori diversi che sono ripetuti almeno 2 volte).
(Punti 2)
Quel e' l'occorrenza massima delle ripetizioni.
(ovvero quante volte e' ripetuto il numero che e' ripetuto per piu' volte)
Nell'esempio e' 3, perche' il 7 e' ripetuto 3 volte
(Punti 2)

B- Avanzato
Si costruisca una funzione che, dato in ingresso un intero, dica:
a. se esistono 2 qualsiasi valori della lista tali per cui la loro somma sia il valore cercato, e le "coordinate" dei 2 valori trovati. (Punti 6)
b. Utilizzando la funzione del punto a, per ciascuno dei seguenti dire se sono la somma di 2 valori della lista, e in che posizione sono tali valori: (Punti 6)

217660
222940
9999999
11155123
18185748

Nella lista d'esempio Fn(11) doverebbe restituire
true, 0, 2 (perche' il primo e il terzo valore sono 1+10=11)

Fn(12)
true, 4, 5

Fn(9)
false

Casi particolari
Fn(20)
false. Anche se 10+10 = 20 Non e' ammesso utilizzare 2 volte lo stesso valore. Devono essere 2 valori presi in posizione diversa

Fn(2)
true, 0, 8 Questa volta 1+1 = 2 e' ammesso, perche' si tratta di due UNI diversi.


C- Esperto
Dire qual e' il piu' grande intero minore di 20.000.000 tale per cui
NON sia la somma di qualsiasi 2 valori presenti nella lista (Punti 14)
Da implementarsi eventualmente come esercizio a parte, usando oppure no la funzione di cui prima, a vostra discrezione.

La complessita', per ciascun esercizio, si calcola a partire dalla sola lista/array gia' costruita, che si intende data come input.


lista dei valori:
http://www.usaupload.net/d/d0x556iuxu4
La prima linea contiene il numero di interi in questo formato
//12345//
Le linee a seguire un record per ciascun intero.
PS: Gli interi sono 100.000 (e quindi la prima riga sara' //100000//)
Si sa che sono stati cercati in modo casuale e uniforme nel range 0 - 10.010.000
(il perche' di questo 10.000 e' solo per questioni di probabilita' relativa alla domanda del 3 esercizio)

cdimauro
22-07-2008, 07:38
Avast mi segnala questo:

"HTML:Agent-L [Expl]"

quando provo a scaricare il file.

P.S. Appena ho un po' di tempo e il file con la lista di numeri provo a cimentarmi. :)

gugoXX
22-07-2008, 08:51
Avast mi segnala questo:

"HTML:Agent-L [Expl]"

quando provo a scaricare il file.

P.S. Appena ho un po' di tempo e il file con la lista di numeri provo a cimentarmi. :)


mmh. E' uno zip con un file di testo... Magari c'e' qualcosa nella pagina di quel server.

shinya
22-07-2008, 09:08
Uff... maledetto firewall aziendale! Non riesco a scaricare il file...

Va beh, ho qualche idea su come risolvere A e B, ma su C ancora non ho trovato niente di furbo...stasera provo qualcosa...

Ma usare strutture dati diverse per i vari punti è ammesso? Cioè, sono da intendersi come 3 esercizi separati o no?

gugoXX
22-07-2008, 09:24
Uff... maledetto firewall aziendale! Non riesco a scaricare il file...

Va beh, ho qualche idea su come risolvere A e B, ma su C ancora non ho trovato niente di furbo...stasera provo qualcosa...

Ma usare strutture dati diverse per i vari punti è ammesso? Cioè, sono da intendersi come 3 esercizi separati o no?

Sisi', devono essere 3 esercizi separati, nel senso che ogni esercizio riparte dalla Lista di input. Poi se si vuole riutilizzare parte del codice scritto in precedenza non e' vietato.
Diciamo 3 funzioni che ricevono in input almeno una lista.
L'importante e' non barare, ovvero non fare assunzioni particolari sui dati in input.
E' stato dato come ordine di grandezze del dominio dei valori il range 0 - 10010000.
Ma se qualcuno volesse essere piu' preciso, e' possibile cercare il massimo valore della lista da utilizzare eventualmente per semplificare qualcosa, ma occorre inserire nel computo anche l'algoritmo per cercarlo.
(Ovvero non vale cercarlo a priori e poi utilizzarelo come costante).
Se tale valore massimo servisse in tutti e 3 gli esercizi, ciascun esercizio dovra' considerare la complessita' di tale ricerca.

shinya
22-07-2008, 09:49
Però scusa non ho capito una cosa...
Nella lista di esempio...con fn(20) perchè dovrebbe tornare "false" quando ci sono il 13 e il 7 che fanno 20?
O era solo per mostrare che non si può usare lo stesso valore? Scusa la domanda scema...

Vincenzo1968
22-07-2008, 09:57
Ciao,

per la lista dobbiamo usare un array o possiamo usare una struttura dati a piacere (array, liste concatenate, etc) ?

gugoXX
22-07-2008, 10:01
Ciao,

per la lista dobbiamo usare un array o possiamo usare una struttura dati a piacere (array, liste concatenate, etc) ?

Quello che vuoi, ma in input e' data una Lista/Array.
Ovvero devi accettarla come input, ma subito dopo puoi farne quello che vuoi.
(Il primo passo sara' quindi la costruzione di un array o lista a partire dal file)

shinya
22-07-2008, 11:38
Questa è la prima soluzione che mi è venuta in mente per il punto B.
Non l'ho provata con il file grande perchè dall'ufficio non riesco a scaricarlo... spero di non aver scritto troppe brutture.

Ho dovuto ordinare la lista, perchè cosi com'era al di là della forza bruta non mi veniva in mente niente di furbo... quindi c'è da aggiungere la complessità del merge sort che usa la classe Collections al suo interno, e l'inizializzazione di tutta la lista usando una class Term che racchiude il numero e la posizione originale. Sarebbe stato più semplice se i requisiti fossero stati i numeri e non le coordinate.

Il costruttore di Contest3 si prende il caso di test...


import java.util.*;

public class Contest3 {
public static void main(String[] args) {
new Contest3(2);
}

public Contest3(int term) {
List<Term> numbers = initList(Arrays.asList(1,13,10,22,5,7,5,3,1,7,3,7));

int[] result = findAddends(numbers, term);
System.out.println(result[0] + " " + result[1]);
}

private List<Term> initList(List<Integer> numbers) {
List<Term> result = new ArrayList<Term>();

for (int i = 0; i < numbers.size(); ++i) {
result.add(this.new Term(numbers.get(i), i));
}
return result;
}

private int[] findAddends(List<Term> numbers, int term) {
int[] pair = new int[2];

Collections.sort(numbers);
int i = 0, j = numbers.size() - 1, sum = 0;
while (i < j) {
sum = numbers.get(i).number + numbers.get(j).number;

while (sum <= term && i < j) {
sum = numbers.get(i).number + numbers.get(j).number;
if (sum == term) {
pair[0] = numbers.get(i).originalPosition;
pair[1] = numbers.get(j).originalPosition;
return pair;
}
i++;
}
j--;
}

return pair;
}

private class Term implements Comparable<Term> {
public Integer number;
public int originalPosition;

public Term(int number, int originalPosition) {
this.number = number;
this.originalPosition = originalPosition;
}

public int compareTo(Term t) {
return number.compareTo(t.number);
}
}
}


Stasera provo con il file grande...

cdimauro
22-07-2008, 13:10
La domanda sorge spontanea: a che serve questo contest? :stordita:

gugoXX
22-07-2008, 13:38
La domanda sorge spontanea: a che serve questo contest? :stordita:

Boh? Dato un input e una domanda trovare i modi piu' efficienti per rispondere...
Direi provare un po' di alternative che non coinvolgano la forza bruta, altrimenti un sistema come quelli che abbiamo oggi non puo' trovare le risposte in tempi decenti.

Albi89
22-07-2008, 13:53
Beh ovviamente mi preparo a ricevere innumerevoli insulti (come saprete ho solo delle misere conoscenze da studentello del primo anno), ma ho affrontato la prima parte del problema così:

void MyList::check_occurrences() {
map<unsigned,unsigned> occurrences;

for (vector<unsigned>::const_iterator it = list.begin(); it != list.end(); ++it)
++occurrences[*it];

map<unsigned, unsigned>::size_type count = 0;
map<unsigned, unsigned>::const_iterator max = occurrences.begin();
for (map<unsigned, unsigned>::const_iterator it = occurrences.begin(); it != occurrences.end(); ++it) {
if (it->second >= 2)
count++;
if (it->second > max->second)
max = it;
}

cout << "Numero elementi ripetuti almeno 2 volte: " << count << endl;
cout << "Elemento piu' frequente: " << max->first << ' ' << max->second << endl;
}

Dopo provo anche il punto B, ma già capisco che le mie soluzioni sono decisamente dispendiose ;)

gugoXX
22-07-2008, 14:07
Però scusa non ho capito una cosa...
Nella lista di esempio...con fn(20) perchè dovrebbe tornare "false" quando ci sono il 13 e il 7 che fanno 20?
O era solo per mostrare che non si può usare lo stesso valore? Scusa la domanda scema...

No, hai perfettamente ragione.
Nell'esempio avrebbe dovuto restutire true, proprio perche almeno 13+7= 20 (ma non perche' 10+10=20)
L'avevo fatto a mano e non me ne ero accorto...

Albi89
22-07-2008, 16:27
Purtroppo la mia versione dell'esercizio B è ancora assai lenta, non so se qualcuno ha provato un approccio "brute force" per compararlo, ma la mia (basata su un vector di coppie di possibili addendi) non è ancora propriamente "scattante".

Vi riporto un output di esempio del programma per confrontarlo coi vostri, appena migliorerò un po' il codice lo posterò ;)

In quest'esecuzione ho testato tutti i valori proposti da gugoXX

Numero elementi ripetuti almeno 2 volte: 459
Elemento piu' frequente: 6361273 4

217660 non e' scomponibile in addendi presenti nella lista

222940 non e' scomponibile in addendi presenti nella lista

9999999 e' la somma dei numeri:
6388096 in posizione 425
3611903 in posizione 70532

11155123 e' la somma dei numeri:
7525320 in posizione 123
3629803 in posizione 70500

18185748 e' la somma dei numeri:
10012786 in posizione 2023
8172962 in posizione 94669

Tempo impiegato: 608.518s

Come potete vedere il tempo di esecuzione è di circa 10 minuti, una piccola infinità.

ndakota
22-07-2008, 16:37
per il tempo di esecuzione in java? c'è qualche classe utile? mi basta il package poi spulcio io le api.. :D

Giullo
22-07-2008, 17:30
ho provato a cimentarmi col punto 2, questo è l'output che ricevo in console


Reading the file and building the list in 0.49909
Sorting the list in 2.415708
Looking for 217660
Looking for 222940
Looking for 9999999
9999999 found! values (7895, 9992104) at positions (3590, 37312) in 0.002228
Looking for 11155123
11155123 found! values (1078115, 10077008) at positions (38441, 92416) in 0.025468
Looking for 18185748
18185748 found! values (8099248, 10086500) at positions (64082, 60049) in 0.401179


qui il codice ruby, fondamentalmente non ho trovato al momento una soluzione migliore di quella di shinya, vediamo se stasera a mente un pò più fresca mi viene in mente qualcosa di diverso :)


#!/usr/bin/ruby -w

class Contest

def initialize(file)
start_time = Time.now
file = File.new(file, "r")
@list_original = []
counter = 0
first = false
while (line = file.gets)
first = true and next if !first
@list_original.push(Item.new(line.to_i, counter))
counter += 1
end
elapsed = Time.now
puts "Reading the file and building the list in #{(elapsed-start_time).to_s}"
file.close
start_time = Time.now
@list_sorted = @list_original.sort {|x,y| x.value <=> y.value }
elapsed = Time.now
puts "Sorting the list in #{(elapsed-start_time).to_s}"
end


def search_for(num)
puts "Looking for "+num.to_s
start_time = Time.now
j = @list_sorted.length-1
i = 0
out = []
while i < j do
sum = @list_sorted[i].value + @list_sorted[j].value
while (sum <= num && i < j) do
ival = @list_sorted[i]
jval = @list_sorted[j]
sum = ival.value + jval.value
if (sum == num)
elapsed = Time.now
out[0] = ival
out[1] = jval
puts "#{num} found! values (#{out[0].value}, #{out[1].value}) at positions (#{out[0].position}, #{out[1].position}) in #{(elapsed-start_time).to_s}"
return out
end
i += 1
end
j -= 1
end
return out
end

end


class Item

attr_accessor :value, :position

def initialize(value, position)
@value = value
@position = position
end

end




c = Contest.new("lista.txt")
c.search_for(217660)
c.search_for(222940)
c.search_for(9999999)
c.search_for(11155123)
c.search_for(18185748)

nico159
22-07-2008, 18:43
Sono riuscito a fare il mio primo programmino che fa qualcosa...e per di più in Python :D
Almeno quattro punti li ho fatti? :sofico:
Dopo vedrò come implementare il resto :oink: class Contest:
numbers = []
def __init__(self, file = None):
if not file:
file = 'lista.txt'
self.__getNumbersFrom(file)

def __getNumbersFrom(self, file):
txt = open(file)
for line in txt:
self.numbers.append( int(line) )
txt.close()

def getRepetition(self):
dictionaryOfAlexandria = { 'unique' : {} }
for number in self.numbers:
if dictionaryOfAlexandria.has_key(number):
dictionaryOfAlexandria[number] += 1
else:
if dictionaryOfAlexandria['unique'].has_key(number):
dictionaryOfAlexandria[number] = 2
del dictionaryOfAlexandria['unique'][number]
else:
dictionaryOfAlexandria['unique'][number] = 1
del dictionaryOfAlexandria['unique']
return dictionaryOfAlexandria

def getKingOfRepetition(self):
repetition = self.getRepetition()
max = None
num = None
for number, repetition in repeated.items():
if repetition > max:
max = repetition
num = number
return (num, max)


Qualcuno ha consigli per eliminare tutti questi if? :stordita:

VICIUS
22-07-2008, 20:07
Carina l'idea dei concorsi :D

Questo è il mio tentativo per i due punti della parte A.
def contest_a1(list)
list.sort!

last = nil
last_dup = last
count = 0

list.each do |current|
if current == last and last_dup != current then
last_dup = current
count += 1
end
last = current
end

return count
end

def contest_a2(list)
list.sort!

last = nil
count = 0
max = 0

list.each do |current|
if current == last then
count+=1
else
if max < count then
max = count
end
count = 0
end
last = current
end

return max + 1
end

marco.r
22-07-2008, 20:48
Esercizio B.
Mancando le closure in C++, fornisco una classe, non una funzione :p


void readFile( const string& filename, vector<int>& numbers )
{
ifstream in(filename.c_str());
numbers.clear();
copy( istream_iterator<int>( in ), istream_iterator<int>(),
back_inserter( numbers ) );
}


class Finder
{
public:
Finder(const string& filename )
{
vector<int> v;
readFile( "lista.txt", v );
for ( unsigned int i=0 ; i<v.size() ; ++i )
{
s.insert( v[i] );
index[ v[i] ] = i;
}

}
bool findNumber( int sum, pair<int,int>& p )
{
for ( set<int>::const_iterator i = s.begin() ; i != s.end() ; ++i )
{
set<int>::const_iterator j = s.find( sum - *i );
if ( j != s.end() )
{
p.first = *i;
p.second = *j;
return true;
}
}
return false;
}
unsigned indexOf( int n )
{
return index[n];
}

private:
set<int> s;
map<int,unsigned int> index;
};

La complessita' dovrebbe essere n*logn. Sulla mia macchina ci mette circa 0.25 secondi compreso il caricamento delle tabelle.

ndakota
22-07-2008, 21:01
per il tempo di esecuzione in java? c'è qualche classe utile? mi basta il package poi spulcio io le api.. :D

mi rispondo da solo.. System.currentTimeMillis() che restituisce un long..

marco.r
22-07-2008, 21:21
Versione alternativa con complessita' lineare... non mi sembra di aver trovato errori...

class Finder
{
public:
Finder(const string& filename )
{
readFile( "lista.txt", v );
for ( unsigned int i=0 ; i<v.size() ; ++i )
{
index[ v[i] ] = i;
}
sort( v.begin(), v.end() );

}

bool findNumber( int sum, pair<int,int>& p )
{
int i=0;
int j=v.size()-1;
while ( i < j )
{
int n = v[i] + v[j];
// cerr << n << ' ' << flush;
if ( n == sum )
{
p.first = v[i];
p.second = v[j];
return true;
}
else if ( n < sum )
{
++i;
}
else
{
--j;
}
}
return false;
}




unsigned indexOf( int n )
{
return index[n];
}

private:
vector<int> v ;
map<int,unsigned int> index;
};


Sulla mia macchina risolve il punto 2 e 3 in circa 1.8 secondi (wall clock)

gugoXX
22-07-2008, 22:21
Versione alternativa con complessita' lineare... non mi sembra di aver trovato errori...
Sulla mia macchina risolve il punto 2 e 3 in circa 1.8 secondi (wall clock)

Non riesco a trovare il codice per il punto 3.
Hai risolto e trovato il valore?

Vedo che e' lineare, ma non l'ho capito.
Quando cambi la j, non ritorni indietro con la i? E perche'?

^TiGeRShArK^
22-07-2008, 22:53
non ho avuto tempo, quindi posto solo A1 e A2 che ho fatto al volo utilizzando linq..
non mi sono nemmeno messo a implementare quello che avevo in mente :p
Domani se ho un pò di tempo posto altro...

var list = File.ReadAllLines("lista.txt").Skip(1).Select(n => int.Parse(n));
var grouped = from n in list
group n by n into g
where g.Count() >= 2
select g.Count();
Console.WriteLine("Risultato A1: {0}, Risultato A2: {1}", grouped.Count(), grouped.Max());

gugoXX
22-07-2008, 23:04
non ho avuto tempo, quindi posto solo A1 e A2 che ho fatto al volo utilizzando linq..
non mi sono nemmeno messo a implementare quello che avevo in mente :p
Domani se ho un pò di tempo posto altro...

var list = File.ReadAllLines("lista.txt").Skip(1).Select(n => int.Parse(n));
var grouped = from n in list
group n by n into g
where g.Count() >= 2
select g.Count();
Console.WriteLine("Risultato A1: {0}, Risultato A2: {1}", grouped.Count(), grouped.Max());


E' un codice molto simile a quanto da me scritto per il problema A.
Ma se mi permetti ci sono 2 "imprecisioni", relative al solo uso di LINQ.
La prima, scrivendo g.Count() 2 volte, la macchina potrebbe fare effettivamente 2 volte il Count() (Non sono assolutamente certo. Ma non sono altrettanto certo che il compilatore possa ottimizzare fino a questo punto)
Per essere piu' tranquillo userei la keyword let.

La seconda e' che l'enumerazione grouped e' solo una definizione di enumerazione, non contiene veramente i valori. Vedila come definizione di un algoritmo.
Cio' significa che quando gli applichi Count() e poi Max(), succede che rifai il lavoro di nuovo daccapo entrambe le volte.
E' sufficiente realizzare fisicamente la lista dell'Enumerazione (ToList()), prima di applicarci sopra Count() e Max()

^TiGeRShArK^
22-07-2008, 23:07
si, ci stavo riflettendo giusto prima :p
ma come ho detto l'ho scritto al volo e non mi sono fermato a pensare + di tanto :D

marco.r
22-07-2008, 23:13
Non riesco a trovare il codice per il punto 3.
Hai risolto e trovato il valore?

Applico beceramente il metodo findNumber per i numeri da 20000000 in giu', la ricerca e' sufficientemente veloce per poterlo fare.


Vedo che e' lineare, ma non l'ho capito.
Quando cambi la j, non ritorni indietro con la i? E perche'?
Visto che e' la terza volta che incarto il browser mentre rispondo, vado in modo molto veloce :p.
Se la vedi dal punto di vista geometrico, se chiami K il valore da cercare, i punti che la cui somma danno quel valore sono quelli della retta x+y = K.
A noi interessano solo quei valori di x e y che appartengono all'insieme { n1,n2,... }. In altri termini, i punti della retta che stanno all'intersezione delle rette di equazione x = ni e y = nj.
La puoi vedere come una griglia lungo cui puoi spostarti in verticale (cambiando l'indice j) o in orizzontale (cambiando l'indice i).
L'idea e' quindi quella di partire dall'angolo in alto a sinistra (i=0,j=MAX) e procedere nel modo seguente: se sono sopra la retta vado in basso (--j), se sono sotto vado a destra (++i). Aggiungo un grafico di esempio da cui spero si capisca chiaramente perche' non occorre mai "tornare su o a sinistra".

gugoXX
22-07-2008, 23:27
Anche la mia implementazione sara' lineare quando avro' tempo di scriverla, ma non avevo pensato di risolverla cosi'.
Vedremo se con il C#, pur essendo piu' lento, mi avvicinero' a quelle tempistiche.

morskott
22-07-2008, 23:36
la mia (costosissima) soluzione (codice pensato in circa 3 secondi, perciò è la piu costosa soluzione possibile (penso)) èimport java.util.*;
import java.io.*;

public class Contest3{
private Map<Integer,Set<Integer>> map;
private int[] vals;

private static class CLIGUI{
static void main(String[] args) throws Exception{
String fileName=args[1];
FileReader fr=new FileReader(fileName);
BufferedReader br=new BufferedReader(fr);
String quantiValori=br.readLine();
int vals=Integer.parseInt(quantiValori.substring(2,quantiValori.length()-2));
List<Integer> values=new LinkedList<Integer>();
for (int i=0;i<vals;i++){
values.add(Integer.parseInt(br.readLine()));
}
int[] vect=new int[values.size()];
for (int i=0;i<vect.length;i++){
vect[i]=values.get(i);
}
br.close();
fr.close();
Contest3 c3=new Contest3(vect);
System.out.println("Numero di valori presenti piu di due volte:"+String.valueOf(c3.quantiAlmeno2volte()));
System.out.println("Numero di occorrenze del numero occorrente piu volte:"+String.valueOf(c3.occorrenzaMassima()));
Map<Integer,Coppia> risVS=c3.testCaseVerificaSomma();
Set<Integer> keySet=risVS.keySet();
for (int i:keySet){
Coppia val=risVS.get(i);
if (val!=null){
System.out.println("Il numero:"+String.valueOf(i)+" risulta la somma dei valori in:"+String.valueOf(val.i)+" e in:"+String.valueOf(val.j));
}else{
System.out.println("Il numero:"+String.valueOf(i)+" non risulta come somma di nessun valore");
}
}
System.out.println("Il piu grande intero non risultante come somma risulta:"+String.valueOf(c3.piuGrandeIntero()));
}
}

public static class Coppia{
int i,j;

Coppia(int i,int j){
this.i=i;
this.j=j;
}
}

public Contest3(int[] vect){
map=new HashMap<Integer,Set<Integer>>();
int j=0;
for (int i:vect){
Set<Integer> val=map.get(i);
if (val==null){
map.put(i,new HashSet<Integer>());
val=map.get(i);
}
val.add(j);
j++;
}
vals=vect;
}

public int quantiAlmeno2volte(){
int ris=0;
Set<Integer> keySet=map.keySet();
for (int i:keySet){
Set<Integer> val=map.get(i);
if (val.size()>=2) ris++;
}
return ris;
}

public int occorrenzaMassima(){
int occ=0;
Set<Integer> valFin=null;
Set<Integer> keySet=map.keySet();
for (int i:keySet){
Set<Integer> val=map.get(i);
if (val.size()>occ){
occ=val.size();
valFin=val;
}
}
return valFin.size();
}

public Coppia verificaSomma(int x){
int curr=vals[0];
int i_curr=0;
for (int i=1;i<vals.length;i++){
int sumCurr=curr+vals[i];
if (sumCurr==x){
return new Coppia(i_curr,i);
}
if (i==vals.length-1){
if (i_curr!=vals.length-1){
i_curr++;
i=i_curr+1;
curr=vals[i_curr];
}
}
}
return null;
}

public Map<Integer,Coppia> testCaseVerificaSomma(){
Map<Integer,Coppia> ris=new HashMap<Integer,Coppia>();
ris.put(217660,this.verificaSomma(217660));
ris.put(222940,this.verificaSomma(222940));
ris.put(9999999,this.verificaSomma(9999999));
ris.put(11155123,this.verificaSomma(11155123));
ris.put(18185748,this.verificaSomma(18185748));
return ris;
}

public int piuGrandeIntero(){
int curr=0;
for (int i=0;i<20000000;i++){
Coppia cop=this.verificaSomma(i);
if (cop==null){
curr=i;
}
}
return curr;
}

public static void main(String[] args) throws Exception{
if (args.length!=0){
if (args[0].equals("cli")){
CLIGUI.main(args);
}
}
}
}risolto tutti i punti, testato tutto (penso funzionante) tranne l'ultimo (sta ancora in esecuzione)

gugoXX
22-07-2008, 23:41
la mia (costosissima) soluzione (codice pensato in circa 3 secondi, perciò è la piu costosa soluzione possibile (penso)) è[code]risolto tutti i punti, testato tutto (penso funzionante) tranne l'ultimo (sta ancora in esecuzione)

Eh... se non esce fuori non hai la sufficienza :)
Se non sbaglio sei a 100.000*100.000*20.000.000 di iterazioni.
mi sa che puoi andare a dormire (e anche domani, e dopodomani...)

morskott
22-07-2008, 23:45
piccola ottimizzazione (almeno per i primi 2 punti)import java.util.*;
import java.io.*;

public class Contest3{
private Map<Integer,Integer> map;
private int[] vals;

private static class CLIGUI{
static void main(String[] args) throws Exception{
String fileName=args[1];
FileReader fr=new FileReader(fileName);
BufferedReader br=new BufferedReader(fr);
String quantiValori=br.readLine();
int vals=Integer.parseInt(quantiValori.substring(2,quantiValori.length()-2));
List<Integer> values=new LinkedList<Integer>();
for (int i=0;i<vals;i++){
values.add(Integer.parseInt(br.readLine()));
}
int[] vect=new int[values.size()];
for (int i=0;i<vect.length;i++){
vect[i]=values.get(i);
}
br.close();
fr.close();
Contest3 c3=new Contest3(vect);
System.out.println("Numero di valori presenti piu di due volte:"+String.valueOf(c3.quantiAlmeno2volte()));
System.out.println("Numero di occorrenze del numero occorrente piu volte:"+String.valueOf(c3.occorrenzaMassima()));
Map<Integer,Coppia> risVS=c3.testCaseVerificaSomma();
Set<Integer> keySet=risVS.keySet();
for (int i:keySet){
Coppia val=risVS.get(i);
if (val!=null){
System.out.println("Il numero:"+String.valueOf(i)+" risulta la somma dei valori in:"+String.valueOf(val.i)+" e in:"+String.valueOf(val.j));
}else{
System.out.println("Il numero:"+String.valueOf(i)+" non risulta come somma di nessun valore");
}
}
System.out.println("Il piu grande intero non risultante come somma risulta:"+String.valueOf(c3.piuGrandeIntero()));
}
}

public static class Coppia{
int i,j;

Coppia(int i,int j){
this.i=i;
this.j=j;
}
}

public Contest3(int[] vect){
map=new HashMap<Integer,Integer>();
for (int i:vect){
Integer val=map.get(i);
if (val==null){
map.put(i,0);
val=map.get(i);
}
map.put(i,val.intValue()+1);
}
vals=vect;
}

public int quantiAlmeno2volte(){
int ris=0;
Set<Integer> keySet=map.keySet();
for (int i:keySet){
int val=map.get(i);
if (val>=2) ris++;
}
return ris;
}

public int occorrenzaMassima(){
int occ=0;
int valFin=-1;
Set<Integer> keySet=map.keySet();
for (int i:keySet){
int val=map.get(i);
if (val>occ){
occ=val;
valFin=val;
}
}
return valFin;
}

public Coppia verificaSomma(int x){
int curr=vals[0];
int i_curr=0;
for (int i=1;i<vals.length;i++){
int sumCurr=curr+vals[i];
if (sumCurr==x){
return new Coppia(i_curr,i);
}
if (i==vals.length-1){
if (i_curr!=vals.length-1){
i_curr++;
i=i_curr+1;
curr=vals[i_curr];
}
}
}
return null;
}

public Map<Integer,Coppia> testCaseVerificaSomma(){
Map<Integer,Coppia> ris=new HashMap<Integer,Coppia>();
ris.put(217660,this.verificaSomma(217660));
ris.put(222940,this.verificaSomma(222940));
ris.put(9999999,this.verificaSomma(9999999));
ris.put(11155123,this.verificaSomma(11155123));
ris.put(18185748,this.verificaSomma(18185748));
return ris;
}

public int piuGrandeIntero(){
int curr=0;
for (int i=0;i<20000000;i++){
Coppia cop=this.verificaSomma(i);
if (cop==null){
curr=i;
}
}
return curr;
}

public static void main(String[] args) throws Exception{
if (args.length!=0){
if (args[0].equals("cli")){
CLIGUI.main(args);
}
}
}
} che ad occhio mi paiono a costo lineare (i primi 2 punti, cioè, quindi manco tanto brutto)

morskott
22-07-2008, 23:47
Eh... se non esce fuori non hai la sufficienza :)
Se non sbaglio sei a 100.000*100.000*20.000.000 di iterazioni.
mi sa che puoi andare a dormire (e anche domani, e dopodomani...)

dici che è leggermente poco efficiente??? :O
Dai che sul mio procio finisce in tempi ragionevoli!!!!! (dici che prima che finisce uscirà l'iPhone 4g???)

Per adesso l'output èNumero di valori presenti piu di due volte:459
Numero di occorrenze del numero occorrente piu volte:4
Il numero:11155123 risulta la somma dei valori in:74 e in:9126
Il numero:18185748 risulta la somma dei valori in:196 e in:6877
Il numero:222940 non risulta come somma di nessun valore
Il numero:217660 non risulta come somma di nessun valore
Il numero:9999999 risulta la somma dei valori in:134 e in:18419

^TiGeRShArK^
23-07-2008, 00:13
lo sapevo che mi passava il sonno... :stordita:

class Contest3
{
List<int> list;

public Contest3()
{
list = File.ReadAllLines("lista.txt").Skip(1).Select(n => int.Parse(n)).ToList();
var grouped = from n in list
group n by n into g
where g.Count() >= 2
select g.Count();
int resultA1 = grouped.Count();
int resultA2 = grouped.Max();
Console.WriteLine("Risultato A1: {0}, Risultato A2: {1}", resultA1, resultA2);
int[] sums = {217660, 222940, 9999999, 11155123, 18185748};
foreach (int sum in sums)
{
int x = 0;
int y = 0;
if (addendsFound(sum, out x, out y))
{
Console.WriteLine("Trovati gli addendi {0} e {1} del numero {2} alle posizioni x = {3}, y = {4}", list[x], list[y], sum, x, y);
}
}

Console.ReadLine();
}

static void Main(string[] args)
{
new Contest3();
}

private bool addendsFound(int sum, out int x, out int y)
{
int[] array = new int[sum];
for (int i = 0; i < list.Count(); i++)
{
if (list[i] < sum)
{
if (array[sum - list[i]] > 0)
{
x = i;
y = array[sum - list[i]] - 1;
return true;
}
else
{
array[list[i]] = i + 1;
}
}
}
x = -1;
y = -1;
return false;
}
}

e l'output:

Risultato A1: 459, Risultato A2: 4
Trovati gli addendi 7581862 e 2418137 del numero 9999999 alle posizioni x = 3184
, y = 2768
Trovati gli addendi 5029681 e 6125442 del numero 11155123 alle posizioni x = 517
2, y = 372
Trovati gli addendi 9546016 e 8639732 del numero 18185748 alle posizioni x = 971
9, y = 7587

Il costo del punto b è lineare nel caso peggiore, in caso gli addendi esistano è mediamente migliore.
Domani vedo di fare anche il punto A + ottimizzato...

VICIUS
23-07-2008, 01:05
Ho provato a risolvere l'ultimo senza usare la funzione della seconda parte. Ho troppo sonno per controllare se ci sono bug ma secondo me funziona. :O
def contest_c1(list, sup)
list.sort!

i = list.size - 1
last = sup
found = nil

while i > 1 do
sum = list[i] + list[i-1]
if sum < sup then
while (sum + 1) < sup && (sum + 1) < last do
sum += 1
found = sum
end
last = sum
else
last = sum
end
break if found != nil
i -= 1
end
return found
end

list = create_list_from_file('lista.txt')
puts contest_b3(list, 20000000)

pierosa
23-07-2008, 01:20
La mia soluzione al punto A


class Contest
def initialize(list)
map = Hash.new(0)
list.each {|i| map[i] += 1}
@occurrences = map.values
end

def contest_a1
@occurrences.select {|v| v >= 2}.length
end

def contest_a2
@occurrences.max
end
end


sono abbastanza pigro, domani vedo gli altri punti

Vincenzo1968
23-07-2008, 01:38
Io sto utilizzando un albero Red-Black(il codice è in C) che ha tempi di ricerca O(lg n) nel caso peggiore.

Molte più linee di codice rispetto agli esempi postati finora, ma dovrebbe valerne la pena.

Vincenzo1968
23-07-2008, 02:00
Sisi', devono essere 3 esercizi separati, nel senso che ogni esercizio riparte dalla Lista di input. Poi se si vuole riutilizzare parte del codice scritto in precedenza non e' vietato.
Diciamo 3 funzioni che ricevono in input almeno una lista.
...

Ciao Gugo,

un chiarimento: con ripartire dalla lista di input intendi rileggere il file ogni volta, o è possibile utilizzare la struttura dati creata al primo punto(per esempio, nel mio caso, l'albero di ricerca) ?

pierosa
23-07-2008, 07:22
ecco il punto b


class ContestB
def initialize(list)
@list = []
list.each_with_index { |e, i| @list << [e,i] }
@sorted_list = @list.sort { |a,b| a[0] <=> b[0] }
end

def contest_b(n)
first = 0
last = @sorted_list.length - 1

while(first < last)
sum = @sorted_list[first][0] + @sorted_list[last][0]
return [true, @sorted_list[first][1], @sorted_list[last][1]] if n == sum
first += 1 if(n > sum)
last -= 1 if(n < sum)
end

return [false]
end
end

list = []
File.open("lista.txt") do |f|
f.each_line { |line| list << line.to_i }
end
list.shift

contest = ContestB.new(list)

values = [217660,222940,9999999,11155123,18185748]

values.each do |item|
res = contest.contest_b(item)
if res[0]
puts "#{item} e' somma degli elementi in posizione #{res[1]}(#{list[res[1]]}) e #{res[2]}(#{list[res[2]]})"
else
puts "#{item} non e' somma di 2 elementi di list"
end
end

gugoXX
23-07-2008, 07:27
Ciao Gugo,

un chiarimento: con ripartire dalla lista di input intendi rileggere il file ogni volta, o è possibile utilizzare la struttura dati creata al primo punto(per esempio, nel mio caso, l'albero di ricerca) ?

Diciamo che si dovrebbe ripartire dalla lista, ma in realta' puoi continuare usando l'albero, solo che l'algoritmo di creazione dell'albero sara' da includere nel computo della complessita' del singolo esercizio.

cdimauro
23-07-2008, 07:38
Punto B, in Python con soluzione lineare:
# Crea la lista
Lista = []
f = open('lista.txt')
f.readline()
for Line in f:
Lista.append(int(Line))
f.close()

# Crea un dizionario (poteva essere creato al punto precedente,
# ma l'esercizio prevedeva come condizione di iniziale
# che soltanto la lista si poteva assumere gia' creata.
Hash = {}
for Indice, Valore in enumerate(Lista):
Posizioni = Hash.get(Valore, [])
Posizioni.append(Indice)
Hash[Valore] = Posizioni

def Fn(Valore):

for Indice, PrimoValore in enumerate(Lista):
SecondoValore = Valore - PrimoValore
Posizioni = Hash.get(SecondoValore, [])
if Posizioni:
if PrimoValore <> SecondoValore:
return True, Indice, Posizioni[0]
elif len(Posizioni) >= 2:
return True, Posizioni[0], Posizioni[1]
return False
Eseguendo questo:
print 217660, Fn(217660)
print 222940, Fn(222940)
print 9999999, Fn(9999999)
print 11155123, Fn(11155123)
print 18185748, Fn(18185748)
ottengo:
217660 False
222940 False
9999999 (True, 134, 18419)
11155123 (True, 74, 9126)
18185748 (True, 196, 68777)

x gugo: Fn(20) con la lista d'esempio non mi dà False, ma True, 1, 5 perché mi prende 13 e 7. :)

EDIT: mi sono accorto soltanto adesso che t'avevo già fatto quest'osservazione. :p

gugoXX
23-07-2008, 07:47
x gugo: Fn(20) con la lista d'esempio non mi dà False, ma True, 1, 5 perché mi prende 13 e 7. :)

Eh lo so. L'ho corretto in qualche post successivo, direi che sarebbe bene se lo correggessi anche nel post originale...

Comunque buono il lineare, e' molto simile al mio per il secondo esercizio.

cdimauro
23-07-2008, 07:54
Aggiungendo il codice per la misurazione dei tempi di calcolo ottengo come output:
Lista creata in 0:00:00.165000
Dizionario creato in 0:00:00.323000
217660 False
Funzione calcolata in 0:00:00.098000
222940 False
Funzione calcolata in 0:00:00.105000
9999999 (True, 134, 18419)
Funzione calcolata in 0:00:00.021000
11155123 (True, 74, 9126)
Funzione calcolata in 0:00:00.016000
18185748 (True, 196, 68777)
Funzione calcolata in 0:00:00.023000
Mi sembra pure abbastanza veloce. :)

Comunque ho evitato di guardare le soluzioni degli altri. Adesso mi leggo con comodo tutto il thread.

cdimauro
23-07-2008, 07:55
DOPPIO.

EDIT. Anzi, lo riuso. :D Ho visto che alcuni hanno preferito ordinare la lista all'inizio, però questo porta la complessità totale a O(n log n).

cdimauro
23-07-2008, 08:24
Soluzione veloce del punto C, riusando il codice del punto B:
import datetime

def CalcTime(StartDate, Header):

EndDate = datetime.datetime.now()
print Header, str(EndDate - StartDate)
return EndDate


# Crea la lista
StartDate = datetime.datetime.now()
Lista = []
f = open('lista.txt')
f.readline()
for Line in f:
Lista.append(int(Line))
f.close()
StartDate = CalcTime(StartDate, 'Lista creata in')

# Crea un dizionario (poteva essere creato al punto precedente,
# ma l'esercizio prevedeva come condizione di iniziale
# che soltanto la lista si poteva assumere gia' creata.
Hash = {}
for Indice, Valore in enumerate(Lista):
Posizioni = Hash.get(Valore, [])
Posizioni.append(Indice)
Hash[Valore] = Posizioni
StartDate = CalcTime(StartDate, 'Dizionario creato in')


def Fn(Valore):

for Indice, PrimoValore in enumerate(Lista):
SecondoValore = Valore - PrimoValore
Posizioni = Hash.get(SecondoValore, [])
if Posizioni:
if PrimoValore <> SecondoValore:
return True, Indice, Posizioni[0]
elif len(Posizioni) >= 2:
return True, Posizioni[0], Posizioni[1]
return False

def BigIntNotFn():

for i in xrange(20000000, 0, -1):
if not Fn(i):
return i
else:
return None

Numero = BigIntNotFn()
if Numero is None:
print 'Non ho trovato nessun intero minore di 20000000 che soddisfi le condizioni.'
else:
print 'Trovato', Numero
StartDate = CalcTime(StartDate, 'Funzione calcolata in')
Ottengo come output:
Lista creata in 0:00:00.220000
Dizionario creato in 0:00:00.357000
Trovato 19991308
Funzione calcolata in 0:00:40.032000
Ovviamente il tempo è O(n) * O(m) con n relativo alla lunghezza della lista (100000) ed m invece pari all'elenco dei numeri da consultare (20000000).

Al momento non mi viene in mente un algoritmo migliore.

marco.r
23-07-2008, 08:33
DOPPIO.

EDIT. Anzi, lo riuso. :D Ho visto che alcuni hanno preferito ordinare la lista all'inizio, però questo porta la complessità totale a O(n log n).

Questione di compromesso.
Se devi fare molte chiamate una volta costruita la funzione, il costo iniziale maggiore puo' essere giustificato, visto che il costo di scorrere un array e' molto piu' basso di un lookup su hash table.
Ad esempio la mia seconda soluzione e' piu' veloce nel punto 3 che non la prima, che dovrebbe essere analoga alla tua (una volta cambiati set e map in hash_set e hash_map).

cdimauro
23-07-2008, 09:10
Ho capito. Comunque al momento non ho esaminato per bene le soluzioni che avete proposto per il punto C (sto cercando di sbatterci la testa per i fatti miei :D).

Posto la soluzione (lineare) al problema A:
import datetime

def CalcTime(StartDate, Header):

EndDate = datetime.datetime.now()
print Header, str(EndDate - StartDate)
return EndDate


# Crea la lista
StartDate = datetime.datetime.now()
Lista = []
f = open('lista.txt')
f.readline()
for Line in f:
Lista.append(int(Line))
f.close()
StartDate = CalcTime(StartDate, 'Lista creata in')

Hash = {}
for Valore in Lista:
Hash[Valore] = Hash.get(Valore, 0) + 1
StartDate = CalcTime(StartDate, 'Dizionario creato in')

print sum(1 for Count in Hash.itervalues() if Count >= 2)
StartDate = CalcTime(StartDate, 'Numero di elementi presenti almeno 2 volte calcolato in')

print max(Count for Count in Hash.itervalues())
StartDate = CalcTime(StartDate, 'Massimo numero di occorrenze calcolato in')
Ottengo:
Lista creata in 0:00:00.245000
Dizionario creato in 0:00:00.120000
459
Numero di elementi presenti almeno 2 volte calcolato in 0:00:00.015000
4
Massimo numero di occorrenze calcolato in 0:00:00.022000

marco.r
23-07-2008, 09:34
Ciao Quaquaraquà! Questa firma è per ricordati la differenza coi veri uomini, di cui tu ovviamente non fai parte visto che l'unico modo che trovi per sfogare la tua rabbia e il tuo odio represso nei miei confronti è quello del ricorso alle mail anonime... Questo perché le nullità come te confrontandosi con me possono soltanto prendere pali da tutte le parti. Come sempre.



Per iniziare a programmare c'è solo Python: http://www.python.it/doc/Howtothink/Howtothink-html-it/index.htm


:mbe:
ho il dubbio che tu abbia qualche problema con la firma :D

^TiGeRShArK^
23-07-2008, 11:09
:mbe:
ho il dubbio che tu abbia qualche problema con la firma :D

confermo :D

^TiGeRShArK^
23-07-2008, 11:23
ecco il mio calcolo dei tempi su un penryn 2.4 .... ma sotto Parallels :D

Risultato A1: 459, Risultato A2: 4
Tempo impiegato per il punto A: 128 ms
Tempo trascorso per il punto B: 4 ms
Tempo trascorso per il punto B: 3 ms
Tempo trascorso per il punto B: 30 ms
Trovati gli addendi 7581862 e 2418137 del numero 9999999 alle posizioni x = 3184, y = 2768
Tempo trascorso per il punto B: 70 ms
Trovati gli addendi 5029681 e 6125442 del numero 11155123 alle posizioni x = 5172, y = 372
Tempo trascorso per il punto B: 157 ms
Trovati gli addendi 9546016 e 8639732 del numero 18185748 alle posizioni x = 9719, y = 7587
Trovato il numero 19999999 che è la somma di 7169 e 4677
Tempo trascorso: 136 ms

Il punto A non è per nulla ottimizzato dato che ho usato il codice precedente, + tardi ne scrivo un'altra versione senza linq per vedere le differenze. :p

^TiGeRShArK^
23-07-2008, 11:48
Ecco il codice con il calcolo dei tempi e con la media.

class Contest3
{
List<int> list;
List<int>[] elapsed = new List<int>[3];

public Contest3()
{
list = File.ReadAllLines("lista.txt").Skip(1).Select(n => int.Parse(n)).ToList();
for (int j = 0; j < 11; j++)
{
Stopwatch watch = Stopwatch.StartNew();
var grouped = from n in list
group n by n into g
let count = g.Count()
where count >= 2
select count;
int resultA1 = grouped.Count();
int resultA2 = grouped.Max();
watch.Stop();
addTime(watch, 0);
Console.WriteLine("Risultato A1: {0}, Risultato A2: {1}", resultA1, resultA2);
Console.WriteLine("Tempo impiegato per il punto A: {0} ms", watch.ElapsedMilliseconds);

int[] sums = { 217660, 222940, 9999999, 11155123, 18185748 };
watch.Reset();
watch.Start();
foreach (int sum in sums)
{
int x = 0;
int y = 0;
bool found = addendsFound(sum, out x, out y);
if (found)
{
Console.WriteLine("Trovati gli addendi {0} e {1} del numero {2} alle posizioni x = {3}, y = {4}", list[x], list[y], sum, x, y);
}
}
watch.Stop();
addTime(watch, 1);
Console.WriteLine("Tempo trascorso per il punto B: {0} ms", watch.ElapsedMilliseconds);
watch.Reset();
watch.Start();

for (int i = 19999999; i >= 0; i++)
{
int x = 0;
int y = 0;
if (addendsFound(i, out x, out y))
{
watch.Stop();
addTime(watch, 2);
Console.WriteLine("Trovato il numero {0} che è la somma di {1} e {2}", i, x, y);
Console.WriteLine("Tempo trascorso: {0} ms", watch.ElapsedMilliseconds);
break;
}
}
}
for (int i = 0; i < elapsed.Length; i++)
{
int time = elapsed[i].Skip(1).Sum() / (elapsed[i].Count - 1);
Console.WriteLine("La media dei tempi per il risultato {0} è {1}", i + 1, time);
}
Console.ReadLine();
}

private void addTime(Stopwatch watch, int result)
{
if (elapsed[result] == null)
{
elapsed[result] = new List<int>();
}
elapsed[result].Add((int)watch.ElapsedMilliseconds);
}

static void Main(string[] args)
{
new Contest3();
}

private bool addendsFound(int sum, out int x, out int y)
{
int[] array = new int[sum];
for (int i = 0; i < list.Count(); i++)
{
if (list[i] < sum)
{
if (array[sum - list[i]] > 0)
{
x = i;
y = array[sum - list[i]] - 1;
return true;
}
else
{
array[list[i]] = i + 1;
}
}
}
x = -1;
y = -1;
return false;
}
}

Se qualche anima pia lo può eseguire su una macchina reale mi sa che è meglio che qui ho una varianza tremenda :p

gugoXX
23-07-2008, 12:25
...

Ma il punto C e' sbagliato.
devi trovare il piu' alto che NON sia la somma di niente...

cdimauro
23-07-2008, 13:14
:mbe:
ho il dubbio che tu abbia qualche problema con la firma :D
confermo :D
Corretta. Grazie per l'avviso e... scusate. :p

^TiGeRShArK^
23-07-2008, 13:22
Ma il punto C e' sbagliato.
devi trovare il piu' alto che NON sia la somma di niente...

doh... avevo capito male :doh:

gugoXX
23-07-2008, 22:02
Ecco il mio miglior prezzo, in C# come sempre.

---------------
First Question
Numero di elementi presenti piu' di una volta: 459
Elemento presente per piu' volte: 6361273, presente 4 volte
Time: 108ms

---------------
Second Question
Elemento 217660 Non Presente
Elemento 222940 Non Presente
Elemento 9999999 Presente come somma di [3184]=7581862 + [2768]=2418137
Elemento 11155123 Presente come somma di [5172]=5029681 + [372]=6125442
Elemento 18185748 Presente come somma di [9719]=9546016 + [7587]=8639732
Time: 23ms

---------------
Third Question
Highest not found: 19991308
Time: 550ms


Ecco il codice.
Avrei ancora un paio di idee per sveltire, ma mi sembra sufficiente :)
Soprattutto non sono riuscito ad ottenere miglioramenti parallelizzando, il che un po' mi dispiace (quando i tempi sono troppo stretti il parallelismo ha troppo overhead).


class Program
{
static void Main(string[] args)
{
string alltext=File.ReadAllText(@"C:\temp\lista.txt");
string[] allwords = alltext.Split(new char[] { '\r', '\n' },StringSplitOptions.RemoveEmptyEntries);
int[] Domain=allwords.Skip(1).Select(t => int.Parse(t)).ToArray();

Stopwatch watch = new Stopwatch();
Console.WriteLine("---------------");
Console.WriteLine("First Question");
watch.Start();
var occ = from val in Domain
group val by val into grp
let cnt=grp.Count()
where cnt > 1
select new ValOcc(grp.Key, cnt);

int tt = occ.Count();
ValOcc umax = occ.Max();
watch.Stop();
Console.WriteLine("Numero di elementi presenti piu' di una volta: {0}",tt);
Console.WriteLine("Elemento presente per piu' volte: {0}, presente {1} volte", umax.Value, umax.Occurrence);
Console.WriteLine("Time: {0}ms", watch.ElapsedMilliseconds);
Console.WriteLine();

Console.WriteLine("---------------");
Console.WriteLine("Second Question");
watch.Reset();
watch.Start();
int[] Val = new[] { 217660, 222940, 9999999, 11155123, 18185748 };

var tmp = Val.Select(t => Question2.WhatPresentAsSum(Domain, t));
var res2 = tmp.ToArray();
watch.Stop();
foreach (var r in res2)
{
if (r.Present) Console.WriteLine("Elemento {0} Presente come somma di [{1}]={2} + [{3}]={4}", r.Value, r.FirstIndex, Domain[r.FirstIndex], r.SecondIndex, Domain[r.SecondIndex]);
else Console.WriteLine("Elemento {0} Non Presente", r.Value);
}
Console.WriteLine("Time: {0}ms", watch.ElapsedMilliseconds);
Console.WriteLine();

Console.WriteLine("---------------");
Console.WriteLine("Third Question");
watch.Reset();
watch.Start();
Question3 tq = new Question3(Domain);
int tv = Enumerable.Range(0, 20000000).Reverse().
First(t => !tq.IsPresentAsSum(t));
watch.Stop();

Console.WriteLine("Highest not found: {0}", tv);
Console.WriteLine("Time: {0}ms", watch.ElapsedMilliseconds);

Console.ReadKey();
}


public class ValOcc : IComparable<ValOcc>
{
public int Value;
public int Occurrence;

public ValOcc(int p_value, int p_occurrence)
{
Value = p_value;
Occurrence = p_occurrence;
}


#region IComparable<ValOcc> Members

public int CompareTo(ValOcc other)
{
return Occurrence.CompareTo(other.Occurrence);
}

#endregion
}
}

public static class Question2
{

public static Question2Result WhatPresentAsSum(int[] Domain,int SearchFor)
{
int domlen=Domain.Length;
Dictionary<int, int> DictValueOcc = new Dictionary<int, int>(domlen);
for (int firstindex = 0; firstindex < domlen; firstindex++)
{
int val = Domain[firstindex];
int search=SearchFor-val;
int secondindex;
if (DictValueOcc.TryGetValue(search,out secondindex))
{
return new Question2Result(){Value = SearchFor, Present=true, FirstIndex=firstindex, SecondIndex=secondindex};
}
DictValueOcc[val]=firstindex;
}
return new Question2Result(){Value= SearchFor, Present=false};
}

public class Question2Result
{
public int Value;
public bool Present;
public int FirstIndex;
public int SecondIndex;
}
}


public class Question3
{
Dictionary<int, int> DictValueOcc;
int[] OrderedArrayOfKeys;
int[] OrderedArrayOfKeysRev;
int MaxValue;

public Question3(IEnumerable<int> Domain)
{
var dd = from val in Domain
group val by val into grp
select new { val = grp.Key, occ = grp.Count() };

DictValueOcc = dd.ToDictionary(t => t.val, t => t.occ);
OrderedArrayOfKeys = DictValueOcc.Keys.OrderBy(t => t).ToArray();
OrderedArrayOfKeysRev = OrderedArrayOfKeys.Reverse().ToArray();

MaxValue = OrderedArrayOfKeys.Last();
}

public bool IsPresentAsSum(int Search)
{
int Half = Search / 2;

int valuehalf;
if (DictValueOcc.TryGetValue(Half,out valuehalf))
{
if (valuehalf > 1) return true;
}

IEnumerable<int> dom = null;
if (Search > MaxValue)
{
dom = OrderedArrayOfKeysRev.TakeWhile(t => t > Half);
}
else
{
dom = OrderedArrayOfKeys.TakeWhile(t => t < Half);
}
bool ret = dom.Any(t => DictValueOcc.ContainsKey(Search - t));
return ret;
}
}

cdimauro
24-07-2008, 07:32
Ho provato a utilizzare Psyco (http://psyco.sourceforge.net/) per accelerare l'esecuzione e ho ottenuto i seguenti risultati:
Lista creata in 0:00:00.137000

Punto A
Funzioni compilate in 0:00:00
Dizionario creato in 0:00:00.062000
459
Numero di elementi presenti almeno 2 volte calcolato in 0:00:00.015000
4
Massimo numero di occorrenze calcolato in 0:00:00.039000

Punto B
Funzioni compilate in 0:00:00.019000
Dizionario creato in 0:00:00.244000
217660 False
Funzione calcolata in 0:00:00.049000
222940 False
Funzione calcolata in 0:00:00.045000
9999999 (True, 134, 18419)
Funzione calcolata in 0:00:00.014000
11155123 (True, 74, 9126)
Funzione calcolata in 0:00:00.024000
18185748 (True, 196, 68777)
Funzione calcolata in 0:00:00.014000

Punto C
Funzioni compilate in 0:00:00.026000
Trovato 19991308
Funzione calcolata in 0:00:13.967000
Mediamente c'è qualche miglioramento, e quello più consistente è sul punto C, che però è ancora basato sul "brute force".

cionci
24-07-2008, 09:39
Punto C:
#include <iostream>
#include <map>
#include <string>
#include <fstream>
#include <algorithm>


using namespace std;



class Contest3
{
map<int,int> addends;
int max;

public:
Contest3(string filename, int max)
{
this->max = max;

ifstream f(filename.c_str());
string buffer;

getline(f, buffer);

while(!f.fail())
{
int number;
f >> number;
addends[number] = 1;
}
};

int search()
{
for(int tested = max; tested > 0; --tested)
{
bool isSuccess = true;
for(map<int,int>::reverse_iterator it = addends.rbegin(); it != addends.rend(); it++)
{
if(addends.find(tested - it->first) != addends.end())
{
isSuccess = false;
break;
}
}
if(isSuccess)
return tested;
}
return 0;
};
};

int main()
{
Contest3 contest("lista.txt", 20000000);
cout << contest.search() << endl;
return 0;
}
~$ g++ contest3.cpp -o contest3
~$ time ./contest3
19991308

real 0m0.681s
user 0m0.680s
sys 0m0.000s
~$ g++ -O3 contest3.cpp -o contest3
~$ time ./contest3
19991308

real 0m0.185s
user 0m0.184s
sys 0m0.000s

Su Core 2 Duo 2166 Mhz

cionci
24-07-2008, 09:43
Il trucco sta tutto nel reverse_iterator ;) Ah, ovviamente non ho ordinato perché il map ordina già le chiavi al momento dell'inserimento.

marco.r
24-07-2008, 11:59
vero.
Mi ero dimenticato che i numeri arrivano fino a 10.000.000

Vincenzo1968
24-07-2008, 18:08
I miei risultati per il punto A:

http://img849.imageshack.us/img849/4089/puntoax.jpg

e questo è il codice:


#include <tchar.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <windows.h>

#define MAX_STACK 1024
#define BUFFER_SIZE 4096

typedef enum tagStati
{
S_ERROR_OPEN_FILE = -2,
S_ERROR = -1,
S0 = 0,
S1
} Stati;

typedef struct tagList
{
int occorrenze;
int numero;
struct tagList *next;
} List;

typedef struct tagTree
{
int numero;
//PosList *lista;
int pos;
int count;
char color;
struct tagTree *father;
struct tagTree *left;
struct tagTree *right;
} Tree;

Tree *pNil = NULL;

List *ListNewNode(int occorrenze, int numero);
void ListInsertNode(List **head, int occorrenze, int numero);
void FreeList(List** head);

void InitNil(Tree **p);
Tree *NewNode(int numero);
Tree *InsertNode(Tree *node, int numero, int pos);
void InsertFixup(Tree **head, Tree **z);
Tree *TreeRotateLeft(Tree *head, Tree *node);
Tree *TreeRotateRight(Tree *head, Tree *node);
void FreeTree(Tree *head);

void InOrder(Tree *head, Tree **temp_max);

Stati DFA(char *szFileName, Tree **pTree);


List *ListNewNode(int occorrenze, int numero)
{
List *r;

r = (List *) malloc(sizeof(List));

if( !r )
{
printf("Memoria insufficiente.\n");
return NULL;
}

r->occorrenze = occorrenze;
r->numero = numero;
r->next = NULL;

return r;
}

void ListInsertNode(List **head, int occorrenze, int numero)
{
List *current = *head;
List *newNode = ListNewNode(occorrenze, numero);

if ( !newNode )
return;

newNode->occorrenze = occorrenze;
newNode->numero = numero;

if ( *head == NULL ||
(*head)->occorrenze <= newNode->occorrenze )
{
newNode->next = *head;
*head = newNode;
}
else
{
while ( current->next != NULL &&
current->next->occorrenze > newNode->occorrenze )
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
}

void FreeList(List** head)
{
List *current = *head;
List *next;

while ( current != NULL )
{
next = current->next;
free(current);
current = next;
}

*head = NULL;
}

void InitNil(Tree **p)
{
*p = NewNode(0);

if ( *p )
{
(*p)->numero = 0;
//(*p)->lista = NULL;
(*p)->pos = 0;
(*p)->count = 0;
(*p)->color = 'b';
(*p)->left = NULL;
(*p)->right = NULL;
(*p)->father = NULL;
}
else
{
printf("Errore nell'inizializzazione di pNil.\n");
}
}

Tree *NewNode(int numero)
{
Tree *r;

r = (Tree *)malloc(sizeof(Tree));

if( !r )
{
_tprintf(_T("Memoria insufficiente.\n"));
return pNil;
}

r->numero = numero;
r->pos = 0;
r->count = 1;
r->color = 'b'; // 'b' = Black; 'r' = Red
r->father = pNil;
r->left = pNil;
r->right = pNil;

return r;
}

Tree *InsertNode(Tree *node, int numero, int pos)
{
int nRes;
Tree *z = pNil;
Tree *y = pNil;
Tree *pRadice = pNil;

z = NewNode(numero);
if ( z == pNil )
return pNil;

pRadice = node;

while ( pRadice != pNil )
{
y = pRadice;

if ( z->numero < pRadice->numero )
nRes = -1;
else if ( z->numero > pRadice->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
pRadice = pRadice->left;
}
else if ( nRes > 0 )
{
pRadice = pRadice->right;
}
else
{
pRadice->count++;
return node;
}
}

z->pos = pos;
z->father = y;
if ( y == pNil )
{
node = z;
}
else
{
if ( z->numero < y->numero )
nRes = -1;
else if ( z->numero > y->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{

y->left = z;
}
else if ( nRes > 0 )
{

y->right = z;
}
else // Trovato
{
y->count++;
return node;
}
}

z->left = pNil;
z->right = pNil;
z->color = 'r'; // Red

InsertFixup(&node, &z);

return node;
}

void InsertFixup(Tree **head, Tree **z)
{
Tree *y = pNil;

while ( (*z)->father->color == 'r' )
{
if ( (*z)->father == (*z)->father->father->left )
{
y = (*z)->father->father->right;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->right )
{
*z = (*z)->father;
*head = TreeRotateLeft(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateRight(*head, (*z)->father->father);
}
}
else
{
y = (*z)->father->father->left;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->left )
{
*z = (*z)->father;
*head = TreeRotateRight(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateLeft(*head, (*z)->father->father);
}
}
}

(*head)->color = 'b';
}

Tree *TreeRotateLeft(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->right == pNil )
return head;

y = node->right;
node->right = y->left;

if ( y->left != pNil )
{
y->left->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->left )
{
node->father->left = y;
}
else
{
node->father->right = y;
}
}

y->left = node;
node->father = y;

return head;
}

Tree *TreeRotateRight(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->left == pNil )
return head;

y = node->left;
node->left = y->right;

if ( y->right != pNil )
{
y->right->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->right )
{
node->father->right = y;
}
else
{
node->father->left = y;
}
}

y->right = node;
node->father = y;

return head;
}

void FreeTree(Tree *head)
{
Tree *temp1, *temp2;

Tree *stack[MAX_STACK];
int top;

top = 0;

if ( head == pNil )
return;

temp1 = temp2 = head;

while ( temp1 != pNil )
{
for(; temp1->left != pNil; temp1 = temp1->left)
stack[top++] = temp1;

while ( (temp1 != pNil) && (temp1->right == pNil || temp1->right == temp2) )
{
temp2 = temp1;
free(temp2);
if ( top == 0 )
return;
temp1 = stack[--top];
}

stack[top++] = temp1;
temp1 = temp1->right;
}
}

void InOrder(Tree *head, Tree **temp_max, int *count)
{
Tree *temp;

int max = 0;

int riga = 0;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return;

temp = head;

(*count) = 0;

while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->left;
}
else
{
_tprintf(_T("Errore: lo stack e' pieno.\n"));
return;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

riga++;
if ( max < temp->count )
{
max = temp->count;
*temp_max = temp;
}
if ( temp->count > 1 )
(*count)++;

temp = temp->right;
}
else
{
break;
}
}
}
}

Stati DFA(char *szFileName, Tree **pTree)
{
Stati stato = S0;
FILE *fp;
char *buffer;
unsigned char c;
int numread = 0;
int k = 0;

int riga;
int num;
int num_righe;
int ultimo_blocco;

errno_t ferr;

riga = 0;
num_righe = 0;

ferr = fopen_s(&fp, szFileName, "rb");
if ( ferr != 0 )
{
printf("Errore nell'apertura del file %s\n", szFileName);
return S_ERROR_OPEN_FILE;
}

/*
fp = fopen(szFileName, "rb");
if ( fp == NULL )
{
printf("Errore nell'apertura del file %s\n", szFileName);
return S_ERROR_OPEN_FILE;
}
*/

buffer = (char*)malloc(sizeof(char)*BUFFER_SIZE + 1);
if ( !buffer )
{
printf("Errore nell'allocazione della memoria.");
fclose(fp);
return -1;
}

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread <= 0 )
{
printf("Il file e' vuoto.\n");
return -1;
}
*(buffer + numread + 1) = '\0';
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

printf("");

k = 0;
while ( *(buffer + k++) != '\n' )
;

num = 0;
while ( 1 )
{
c = *(buffer + k++);
if ( c == EOF )
break;

if ( c == '\0' )
{
k = 0;
if ( ultimo_blocco )
break;

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

*(buffer + numread + 1) = '\0';

c = *(buffer + k++);
}

if ( c == '\n' )
{
riga++;
if ( riga > 100001 )
{
printf("Errore: database troppo grande.\n");
fclose(fp);
return S_ERROR;
}
stato = S0;
}

switch (stato)
{
case S0:
num = 0;
if ( c >= '0' && c <= '9' )
{
num = c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
stato = S0;
}
else
{
printf("\nErrore in S0 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;

case S1:
if ( c >= '0' && c <= '9' )
{
num = num * 10 + c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
*pTree = InsertNode(*pTree, num, riga);
//printf("Numero -> %d <> Riga ->%d\n", num, riga);
num = 0;
stato = S0;
}
else
{
printf("\nErrore in S1 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;
}
}

free(buffer);

if ( fp )
fclose(fp);

return stato;
}

int main()
{
Stati stato;
Tree *p = NULL;
Tree *pmax = NULL;

DWORD ms = GetTickCount();

int count;

InitNil(&pNil);

p = pNil;
pmax = pNil;

stato = DFA("C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista\\lista.txt", &p);

if( stato == S0 || stato == S1 )
{
InOrder(p, &pmax, &count);
printf("\nNumero elementi presenti piu' volte -> %d\n", count);
printf("Numero %d presente %d volte\n", pmax->numero, pmax->count);
printf("Time -> %dms\n", GetTickCount() - ms);
}
else
{
printf("\nL'automa ha restituito un errore.\n");
return -1;
}

return 0;
}

gugoXX
24-07-2008, 18:32
Mamma mia Vincenzo.
Ma un una vita precedente sei stato un monaco amanuense? Complimenti per la forza di volonta'.
Scherzo... ma a vedere quanto avrei dovuto scrivere in C, il C# mi piace sempre di piu'.


---------------
First Question
Numero di elementi presenti piu' di una volta: 459
Elemento presente per piu' volte: 6361273, presente 4 volte
Time: 58ms

Vincenzo1968
24-07-2008, 19:25
Mamma mia Vincenzo.
Ma un una vita precedente sei stato un monaco amanuense? Complimenti per la forza di volonta'.
Scherzo... ma a vedere quanto avrei dovuto scrivere in C, il C# mi piace sempre di piu'.


---------------
First Question
Numero di elementi presenti piu' di una volta: 459
Elemento presente per piu' volte: 6361273, presente 4 volte
Time: 58ms


Ciao Gugo,

No, non in una vita precedente, ma in quella attuale. Sono un monaco e, non avendo niente da fare in convento, passo il tempo a scrivere codice C.
Ho visto che hai migliorato il tempo per il punto A. Puoi postare il codice? Non perché non mi fidi ma, alla fine, vorrei postare i tempi di tutti presi su una sola macchina(che ha più senso, no?).

Ciao.

P.S.
Prima scherzavo, non sono un monaco.

gugoXX
24-07-2008, 20:05
Ciao Gugo,
No, non in una vita precedente, ma in quella attuale. Sono un monaco e, non avendo niente da fare in convento, passo il tempo a scrivere codice C.
ahahah...

comunque si', certo, ha piu' senso presi sulla stessa macchina.
A casa il nuovo codice per il punto A si assesta a 35ms
Eccolo. Aggiunto una riga (facevo il lavoro di raggruppamento 2 volte)
E mi ero dimenticato di compilare in Release (rospo)

Il codice per il solo punto A

static void Main(string[] args)
{
string alltext=File.ReadAllText(@"C:\temp\lista.txt");
string[] allwords = alltext.Split(new char[] { '\r', '\n' },StringSplitOptions.RemoveEmptyEntries);
int[] Domain=allwords.Skip(1).Select(t => int.Parse(t)).ToArray();

Stopwatch watch = new Stopwatch();
Console.WriteLine("---------------");
Console.WriteLine("First Question");
watch.Start();
var occ = from val in Domain
group val by val into grp
let cnt=grp.Count()
where cnt > 1
select new ValOcc(grp.Key, cnt);

var occarr = occ.ToArray();

int tt = occarr.Count();
ValOcc umax = occarr.Max();
watch.Stop();
Console.WriteLine("Numero di elementi presenti piu' di una volta: {0}",tt);
Console.WriteLine("Elemento presente per piu' volte: {0}, presente {1} volte", umax.Value, umax.Occurrence);
Console.WriteLine("Time: {0}ms", watch.ElapsedMilliseconds);
}

public class ValOcc : IComparable<ValOcc>
{
public int Value;
public int Occurrence;

public ValOcc(int p_value, int p_occurrence)
{
Value = p_value;
Occurrence = p_occurrence;
}


#region IComparable<ValOcc> Members

public int CompareTo(ValOcc other)
{
return Occurrence.CompareTo(other.Occurrence);
}

#endregion
}

Vincenzo1968
24-07-2008, 21:39
I miei risultati per il punto B:

http://img542.imageshack.us/img542/8465/puntob.jpg

e questo è il codice:


#include <tchar.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <windows.h>

#define MAX_STACK 1024
#define BUFFER_SIZE 4096

typedef enum tagStati
{
S_ERROR_OPEN_FILE = -2,
S_ERROR = -1,
S0 = 0,
S1
} Stati;

typedef struct tagList
{
int occorrenze;
int numero;
struct tagList *next;
} List;

typedef struct tagTree
{
int numero;
int pos;
int count;
char color;
struct tagTree *father;
struct tagTree *left;
struct tagTree *right;
} Tree;

Tree *pNil = NULL;

List *ListNewNode(int occorrenze, int numero);
void ListInsertNode(List **head, int occorrenze, int numero);
void FreeList(List** head);

void InitNil(Tree **p);
Tree *NewNode(int numero);
Tree *InsertNode(Tree *node, int numero, int pos);
void InsertFixup(Tree **head, Tree **z);
Tree *TreeRotateLeft(Tree *head, Tree *node);
Tree *TreeRotateRight(Tree *head, Tree *node);
void Search(Tree *head, Tree **result, int key);
void FreeTree(Tree *head);

void InOrder(Tree *head, Tree **temp_max, int *count);

Stati DFA(char *szFileName, Tree **pTree);

int EsisteSomma(Tree *head, int somma, int *n1, int *n2, int *pos1, int *pos2);

int EsisteSomma(Tree *head, int somma, int *n1, int *n2, int *pos1, int *pos2)
{
Tree *temp;
Tree *findTree = pNil;

int diff = 0;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return 0;

temp = head;

while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->left;
}
else
{
_tprintf(_T("Errore: lo stack e' pieno.\n"));
return 0;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

diff = somma - temp->numero;
if ( diff < 0 )
return 0;

Search(head, &findTree, diff);
if ( findTree != pNil && temp != pNil )
{
*n1 = temp->numero;
*n2 = findTree->numero;

*pos1 = temp->pos;
*pos2 = findTree->pos;

return 1;
}

temp = temp->right;
}
else
{
break;
}
}
}

return 0;
}

List *ListNewNode(int occorrenze, int numero)
{
List *r;

r = (List *) malloc(sizeof(List));

if( !r )
{
printf("Memoria insufficiente.\n");
return NULL;
}

r->occorrenze = occorrenze;
r->numero = numero;
r->next = NULL;

return r;
}

void ListInsertNode(List **head, int occorrenze, int numero)
{
List *current = *head;
List *newNode = ListNewNode(occorrenze, numero);

if ( !newNode )
return;

newNode->occorrenze = occorrenze;
newNode->numero = numero;

if ( *head == NULL ||
(*head)->occorrenze <= newNode->occorrenze )
{
newNode->next = *head;
*head = newNode;
}
else
{
while ( current->next != NULL &&
current->next->occorrenze > newNode->occorrenze )
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
}

void FreeList(List** head)
{
List *current = *head;
List *next;

while ( current != NULL )
{
next = current->next;
free(current);
current = next;
}

*head = NULL;
}

void InitNil(Tree **p)
{
*p = NewNode(0);

if ( *p )
{
(*p)->numero = 0;
(*p)->pos = 0;
(*p)->count = 0;
(*p)->color = 'b';
(*p)->left = NULL;
(*p)->right = NULL;
(*p)->father = NULL;
}
else
{
printf("Errore nell'inizializzazione di pNil.\n");
}
}

Tree *NewNode(int numero)
{
Tree *r;

r = (Tree *)malloc(sizeof(Tree));

if( !r )
{
_tprintf(_T("Memoria insufficiente.\n"));
return pNil;
}

r->numero = numero;
r->pos = 0;
r->count = 1;
r->color = 'b'; // 'b' = Black; 'r' = Red
r->father = pNil;
r->left = pNil;
r->right = pNil;

return r;
}

Tree *InsertNode(Tree *node, int numero, int pos)
{
int nRes;
Tree *z = pNil;
Tree *y = pNil;
Tree *pRadice = pNil;

z = NewNode(numero);
if ( z == pNil )
return pNil;

pRadice = node;

while ( pRadice != pNil )
{
y = pRadice;

if ( z->numero < pRadice->numero )
nRes = -1;
else if ( z->numero > pRadice->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
pRadice = pRadice->left;
}
else if ( nRes > 0 )
{
pRadice = pRadice->right;
}
else
{
pRadice->count++;
return node;
}
}

z->pos = pos;
z->father = y;
if ( y == pNil )
{
node = z;
}
else
{
if ( z->numero < y->numero )
nRes = -1;
else if ( z->numero > y->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
y->left = z;
}
else if ( nRes > 0 )
{
y->right = z;
}
else // Trovato
{
y->count++;
return node;
}
}

z->left = pNil;
z->right = pNil;
z->color = 'r'; // Red

InsertFixup(&node, &z);

return node;
}

void InsertFixup(Tree **head, Tree **z)
{
Tree *y = pNil;

while ( (*z)->father->color == 'r' )
{
if ( (*z)->father == (*z)->father->father->left )
{
y = (*z)->father->father->right;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->right )
{
*z = (*z)->father;
*head = TreeRotateLeft(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateRight(*head, (*z)->father->father);
}
}
else
{
y = (*z)->father->father->left;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->left )
{
*z = (*z)->father;
*head = TreeRotateRight(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateLeft(*head, (*z)->father->father);
}
}
}

(*head)->color = 'b';
}

Tree *TreeRotateLeft(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->right == pNil )
return head;

y = node->right;
node->right = y->left;

if ( y->left != pNil )
{
y->left->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->left )
{
node->father->left = y;
}
else
{
node->father->right = y;
}
}

y->left = node;
node->father = y;

return head;
}

Tree *TreeRotateRight(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->left == pNil )
return head;

y = node->left;
node->left = y->right;

if ( y->right != pNil )
{
y->right->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->right )
{
node->father->right = y;
}
else
{
node->father->left = y;
}
}

y->right = node;
node->father = y;

return head;
}

void FreeTree(Tree *head)
{
Tree *temp1, *temp2;

Tree *stack[MAX_STACK];
int top;

top = 0;

if ( head == pNil )
return;

temp1 = temp2 = head;

while ( temp1 != pNil )
{
for(; temp1->left != pNil; temp1 = temp1->left)
stack[top++] = temp1;

while ( (temp1 != pNil) && (temp1->right == pNil || temp1->right == temp2) )
{
temp2 = temp1;
free(temp2);
if ( top == 0 )
return;
temp1 = stack[--top];
}

stack[top++] = temp1;
temp1 = temp1->right;
}
}

void InOrder(Tree *head, Tree **temp_max, int *count)
{
Tree *temp;

int max = 0;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return;

temp = head;

(*count) = 0;

while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->left;
}
else
{
_tprintf(_T("Errore: lo stack e' pieno.\n"));
return;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

if ( max < temp->count )
{
max = temp->count;
*temp_max = temp;
}
if ( temp->count > 1 )
(*count)++;

temp = temp->right;
}
else
{
break;
}
}
}
}

Stati DFA(char *szFileName, Tree **pTree)
{
Stati stato = S0;
FILE *fp;
char *buffer;
unsigned char c;
int numread = 0;
int k = 0;

int riga;
int num;
int num_righe;
int ultimo_blocco;

errno_t ferr;

riga = 0;
num_righe = 0;

ferr = fopen_s(&fp, szFileName, "rb");
if ( ferr != 0 )
{
printf("Errore nell'apertura del file %s\n", szFileName);
return S_ERROR_OPEN_FILE;
}

buffer = (char*)malloc(sizeof(char)*BUFFER_SIZE + 1);
if ( !buffer )
{
printf("Errore nell'allocazione della memoria.");
fclose(fp);
return -1;
}

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread <= 0 )
{
printf("Il file e' vuoto.\n");
return -1;
}
*(buffer + numread + 1) = '\0';
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

printf("");

k = 0;
while ( *(buffer + k++) != '\n' )
;

num = 0;
while ( 1 )
{
c = *(buffer + k++);
if ( c == EOF )
break;

if ( c == '\0' )
{
k = 0;
if ( ultimo_blocco )
break;

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

*(buffer + numread + 1) = '\0';

c = *(buffer + k++);
}

switch (stato)
{
case S0:
num = 0;
if ( c >= '0' && c <= '9' )
{
num = c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
stato = S0;
}
else
{
printf("\nErrore in S0 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;

case S1:
if ( c >= '0' && c <= '9' )
{
num = num * 10 + c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
riga++;
*pTree = InsertNode(*pTree, num, riga);
num = 0;
stato = S0;
}
else
{
printf("\nErrore in S1 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;
}
}

free(buffer);

if ( fp )
fclose(fp);

return stato;
}

void Search(Tree *head, Tree **result, int key)
{
Tree *node;

*result = pNil;
node = head;

if ( head == pNil )
return;

while( 1 )
{
if ( key < node->numero )
{
if ( node->left == pNil )
break;
node = node->left;
}
else if ( key > node->numero )
{
if ( node->right == pNil )
break;
node = node->right;
}
else // key == node->data
{
*result = node;
break;
}
}
}

int main()
{
Stati stato;
Tree *p = NULL;
Tree *pmax = NULL;

int n1, n2, pos1, pos2;
int somma;

DWORD ms = GetTickCount();

InitNil(&pNil);

p = pNil;
pmax = pNil;

stato = DFA("C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista\\lista.txt", &p);

if( stato == S0 || stato == S1 )
{
somma = 217660;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 222940;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 9999999;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 11155123;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 18185748;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

printf("\nTime -> %dms\n", GetTickCount() - ms);
}
else
{
printf("\nL'automa ha restituito un errore.\n");
return -1;
}

return 0;
}

ndakota
24-07-2008, 21:43
mamma mia vincenzo i tuoi sorgenti sono sempre papiri(e vorrei vedere :D ).. e a prestazioni rispetto agli altri linguaggi come c# e python come siamo messi?

Vincenzo1968
24-07-2008, 21:57
mamma mia vincenzo i tuoi sorgenti sono sempre papiri(e vorrei vedere :D ).. e a prestazioni rispetto agli altri linguaggi come c# e python come siamo messi?

Ciao ndakota,

Il C è, generalmente, più veloce rispetto al C#:

http://www.hwupgrade.it/forum/showthread.php?t=1779822

Potrei snellire un po' il codice utilizzando, per esempio, le funzioni del C come fscanf per leggere i numeri dal file, ma preferisco usare un DFA che è più efficiente:

http://forum.html.it/forum/showthread.php?s=&threadid=1257749

A proposito, volevo chiedere a Gugo se i tempi di lettura dal file vanno compresi(in tutti e tre i punti) o se bisogna prendere solo quelli degli algoritmi di ricerca.

Ciao

Vincenzo1968
24-07-2008, 22:21
La complessita', per ciascun esercizio, si calcola a partire dalla sola lista/array gia' costruita, che si intende data come input.



Se non si devono calcolare i tempi di lettura dal file, come ho visto hai fatto tu:


static void Main(string[] args)
{
string alltext=File.ReadAllText(@"C:\temp\lista.txt");
string[] allwords = alltext.Split(new char[] { '\r', '\n' },StringSplitOptions.RemoveEmptyEntries);
int[] Domain=allwords.Skip(1).Select(t => int.Parse(t)).ToArray();

Stopwatch watch = new Stopwatch();
Console.WriteLine("---------------");
Console.WriteLine("First Question");
watch.Start();
...


questi sono i miei risultati per il punto A:

http://img844.imageshack.us/img844/1/puntoa2.jpg

e questi sono quelli per il punto B;

http://img803.imageshack.us/img803/5258/puntob2.jpg

gugoXX
24-07-2008, 23:01
Ciao Vincenzo.

Ma mentre leggi stai gia' inserendo in una struttura che non e' un semplice array o una semplice lista o sbaglio?
Poi non cambiera' nulla pero'...

Vincenzo1968
24-07-2008, 23:17
Ciao Vincenzo.

Ma mentre leggi stai gia' inserendo in una struttura che non e' un semplice array o una semplice lista o sbaglio?
Poi non cambiera' nulla pero'...

Si, inserisco i valori letti dal file direttamente nell'albero.
Modifico il codice in modo da creare un array e da questo, in seguito, costruisco l'albero. I tempi li calcolo a partire dalla costruzione dell'albero dall'array, giusto?

Ciao

gugoXX
24-07-2008, 23:25
Si, inserisco i valori letti dal file direttamente nell'albero.
Modifico il codice in modo da creare un array e da questo, in seguito, costruisco l'albero. I tempi li calcolo a partire dalla costruzione dell'albero dall'array, giusto?

Ciao

Si, ma non darti pena, secondo me non cambia nulla.
Sono solo 100.000 valori

Per inciso, stavo cercando di formulare un nuovo contest in cui risultasse troppo dispendioso ordinare e siu dovesser fare direttamente valutazioni sull'elenco disordinato.
Il testo voleva essere qualcosa tipo: Hai un elenco disordinato di X elementi, contenenti tutti gli elementi compresi tra 0 e X+1. Ne manca uno, trova qual e'.
In pratica, una prima esecuzione potrebbe essere quella di ordinare tutto l'elenco, per poi riscorrerlo e cercare il mancante.

Peccato che anche in C#, con 50milioni di elementi, viene ordinato tutto in meno di 1 secondo.
Abbiamo macchine troppo veloci.

Vincenzo1968
25-07-2008, 00:02
Si, ma non darti pena, secondo me non cambia nulla.
Sono solo 100.000 valori

Per inciso, stavo cercando di formulare un nuovo contest in cui risultasse troppo dispendioso ordinare e siu dovesser fare direttamente valutazioni sull'elenco disordinato.
Il testo voleva essere qualcosa tipo: Hai un elenco disordinato di X elementi, contenenti tutti gli elementi compresi tra 0 e X+1. Ne manca uno, trova qual e'.
In pratica, una prima esecuzione potrebbe essere quella di ordinare tutto l'elenco, per poi riscorrerlo e cercare il mancante.

Peccato che anche in C#, con 50milioni di elementi, viene ordinato tutto in meno di 1 secondo.
Abbiamo macchine troppo veloci.

Purtroppo(per me ;) ) le cose cambiano:

Questi soni i risultati

Punto A:
http://img841.imageshack.us/img841/8693/puntoa2new.jpg

Punto B:
http://img515.imageshack.us/img515/2986/puntob2new.jpg

Questa è la funzione main del punto A:

int main()
{
int a[100000];
Stati stato;
Tree *p = NULL;
Tree *pmax = NULL;

DWORD ms;

int k;
int count;

InitNil(&pNil);

p = pNil;
pmax = pNil;

stato = DFA("C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista\\lista.txt", a);

ms = GetTickCount();

for( k = 0; k < 100000; k++ )
p = InsertNode(p, *(a+k), k);

if( stato == S0 || stato == S1 )
{
InOrder(p, &pmax, &count);
printf("\nNumero elementi presenti piu' volte -> %d\n", count);
printf("Numero %d presente %d volte\n", pmax->numero, pmax->count);
printf("Time -> %dms\n", GetTickCount() - ms);
}
else
{
printf("\nL'automa ha restituito un errore.\n");
return -1;
}

return 0;
}


e questa è quella del punto B:

int main()
{
int a[100000];
Stati stato;
Tree *p = NULL;
Tree *pmax = NULL;

int n1, n2, pos1, pos2;
int somma;
int k;

DWORD ms;

InitNil(&pNil);

p = pNil;
pmax = pNil;

stato = DFA("C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista\\lista.txt", a);

for( k = 0; k < 100000; k++ )
//p = InsertNode(&(*p), *(a+k), k);
p = InsertNode(p, *(a+k), k);

ms = GetTickCount();

if( stato == S0 || stato == S1 )
{
somma = 217660;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 222940;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 9999999;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 11155123;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

somma = 18185748;
if ( !EsisteSomma(p, somma, &n1, &n2, &pos1, &pos2) )
{
printf("\nNon ci sono numeri che sommano %d\n\n", somma);
}
else
{
printf("i numeri %d e %d sommano %d\n", n1, n2, somma);
printf("Le loro posizioni nella lista sono:\n");
printf("%d in posizione %d\n", n1, pos1);
printf("%d in posizione %d\n\n", n2, pos2);
}

printf("\nTime -> %dms\n", GetTickCount() - ms);
}
else
{
printf("\nL'automa ha restituito un errore.\n");
return -1;
}

return 0;
}


Il resto del codice non è cambiato tranne il DFA che adesso accetta come parametro un puntatore a int invece che all'albero:


Stati DFA(char *szFileName, int *pArray)


Il puntatore, all'interno della funzione è utilizzato come segue:


...
case S1:
if ( c >= '0' && c <= '9' )
{
num = num * 10 + c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
//*pTree = InsertNode(*pTree, num, riga);
*(pArray + riga) = num;
riga++;
num = 0;
stato = S0;
}
else
{
printf("\nErrore in S1 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;
...

morskott
25-07-2008, 01:56
Risolto tutto in tempo lineare (almeno credo), non ho ancora messo i tempi per ogni provaimport java.util.*;
import java.io.*;

public class Contest3{
private Map<Integer,CoppiaIn> map;
private int[] vals;

private static class CLIGUI{
static void main(String[] args) throws Exception{
String fileName=args[1];
FileReader fr=new FileReader(fileName);
BufferedReader br=new BufferedReader(fr);
String quantiValori=br.readLine();
int vals=Integer.parseInt(quantiValori.substring(2,quantiValori.length()-2));
List<Integer> values=new LinkedList<Integer>();
for (int i=0;i<vals;i++){
values.add(Integer.parseInt(br.readLine()));
}
int[] vect=new int[values.size()];
for (int i=0;i<vect.length;i++){
vect[i]=values.get(i);
}
br.close();
fr.close();
Contest3 c3=new Contest3(vect);
System.out.println("Numero di valori presenti piu di due volte:"+String.valueOf(c3.quantiAlmeno2volte()));
System.out.println("Numero di occorrenze del numero occorrente piu volte:"+String.valueOf(c3.occorrenzaMassima()));
Map<Integer,Coppia> risVS=c3.testCaseVerificaSomma();
Set<Integer> keySet=risVS.keySet();
for (int i:keySet){
Coppia val=risVS.get(i);
if (val!=null){
System.out.println("Il numero:"+String.valueOf(i)+" risulta la somma dei valori in:"+String.valueOf(val.i)+" e in:"+String.valueOf(val.j));
}else{
System.out.println("Il numero:"+String.valueOf(i)+" non risulta come somma di nessun valore");
}
}
System.out.println("Il piu grande intero non risultante come somma risulta:"+String.valueOf(c3.piuGrandeIntero()));
}
}

public static class Coppia{
int i,j;

Coppia(int i,int j){
this.i=i;
this.j=j;
}
}

private static class CoppiaIn{
int occorrenze;
List<Integer> indici;

CoppiaIn(){
this.occorrenze=0;
this.indici=new LinkedList<Integer>();
}
}

public Contest3(int[] vect){
map=new HashMap<Integer,CoppiaIn>();
for (int i=0;i<vect.length;i++){
CoppiaIn val=map.get(vect[i]);
if (val==null){
map.put(vect[i],new CoppiaIn());
val=map.get(vect[i]);
}
val.occorrenze++;
val.indici.add(i);
}
vals=vect;
}

public int quantiAlmeno2volte(){
int ris=0;
Set<Integer> keySet=map.keySet();
for (int i:keySet){
CoppiaIn val=map.get(i);
if (val.occorrenze>=2) ris++;
}
return ris;
}

public int occorrenzaMassima(){
int occ=0;
int valFin=-1;
Set<Integer> keySet=map.keySet();
for (int i:keySet){
CoppiaIn val=map.get(i);
if (val.occorrenze>occ){
occ=val.occorrenze;
valFin=val.occorrenze;
}
}
return valFin;
}

public Coppia verificaSomma(int x){
Set<Integer> keySet=map.keySet();
for (int i:keySet){
int resto=x-i;
CoppiaIn val=map.get(resto);
if (val!=null){
CoppiaIn att=map.get(i);
if (i!=resto){
return new Coppia(att.indici.get(0),val.indici.get(0));
}else{
if (att.indici.size()==2){
return new Coppia(att.indici.get(0),val.indici.get(1));
}else
return null;
}
}
}
return null;
}

public Map<Integer,Coppia> testCaseVerificaSomma(){
Map<Integer,Coppia> ris=new HashMap<Integer,Coppia>();
ris.put(217660,this.verificaSomma(217660));
ris.put(222940,this.verificaSomma(222940));
ris.put(9999999,this.verificaSomma(9999999));
ris.put(11155123,this.verificaSomma(11155123));
ris.put(18185748,this.verificaSomma(18185748));
return ris;
}

public int piuGrandeIntero(){
int curr=0;
for (int i=20000000;i>=0;i--){
Coppia cop=this.verificaSomma(i);
if (cop==null){
return i;
}
}
return curr;
}

public static void main(String[] args) throws Exception{
if (args.length!=0){
if (args[0].equals("cli")){
CLIGUI.main(args);
}
}
}
}in pratica creo un map che mappa i numeri trovati con le occorrenze del numero e gli indici dove sono posizionati, le occorrenze maggiori di 2 basta che scorro il map e controllo il numero di occorrenze precedentemente settato, per vedere l'occorrenza massima prendo il massimo di tutte le occorrenze e per vedere la somma per ogni numero dentro il map calcolo il resto della somma, cioè quanto gli manca per arrivare al numero cercato, faccio una get sul map del numero trovato e se mi torna qualcosa diverso da null mando come risultato l'indice corrente e l'indice dell'elemento trovato. Per il massimo numero non somma scorro partendo dal numero massimo fino a trovare un indice che chiamando la funzione precedente mi torni null.

cionci
25-07-2008, 11:11
Risolto tutto in tempo lineare (almeno credo),
La parte 3 è sicuramente O(m) * O(n).

Vincenzo1968
25-07-2008, 11:15
Questi sono i risultati per il punto C:

http://img850.imageshack.us/img850/2520/puntocu.jpg

e questo è il codice:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <windows.h>

#define MAX_STACK 1024
#define BUFFER_SIZE 4096

typedef enum tagStati
{
S_ERROR_OPEN_FILE = -2,
S_ERROR = -1,
S0 = 0,
S1
} Stati;

typedef struct tagList
{
int occorrenze;
int numero;
struct tagList *next;
} List;

typedef struct tagTree
{
int numero;
int pos;
int count;
char color;
struct tagTree *father;
struct tagTree *left;
struct tagTree *right;
} Tree;

Tree *pNil = NULL;

List *ListNewNode(int occorrenze, int numero);
void ListInsertNode(List **head, int occorrenze, int numero);
void FreeList(List** head);

void InitNil(Tree **p);
Tree *NewNode(int numero);
Tree *InsertNode(Tree *node, int numero, int pos);
void InsertFixup(Tree **head, Tree **z);
Tree *TreeRotateLeft(Tree *head, Tree *node);
Tree *TreeRotateRight(Tree *head, Tree *node);
void Search(Tree *head, Tree **result, int key);
void TreeMinimum(Tree *head, Tree **result);
void FreeTree(Tree *head);

Stati DFA(char *szFileName, int *pArray);

List *ListNewNode(int occorrenze, int numero)
{
List *r;

r = (List *) malloc(sizeof(List));

if( !r )
{
printf("Memoria insufficiente.\n");
return NULL;
}

r->occorrenze = occorrenze;
r->numero = numero;
r->next = NULL;

return r;
}

void ListInsertNode(List **head, int occorrenze, int numero)
{
List *current = *head;
List *newNode = ListNewNode(occorrenze, numero);

if ( !newNode )
return;

newNode->occorrenze = occorrenze;
newNode->numero = numero;

if ( *head == NULL ||
(*head)->occorrenze <= newNode->occorrenze )
{
newNode->next = *head;
*head = newNode;
}
else
{
while ( current->next != NULL &&
current->next->occorrenze > newNode->occorrenze )
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
}

void FreeList(List** head)
{
List *current = *head;
List *next;

while ( current != NULL )
{
next = current->next;
free(current);
current = next;
}

*head = NULL;
}

void InitNil(Tree **p)
{
*p = NewNode(0);

if ( *p )
{
(*p)->numero = 0;
(*p)->pos = 0;
(*p)->count = 0;
(*p)->color = 'b';
(*p)->left = NULL;
(*p)->right = NULL;
(*p)->father = NULL;
}
else
{
printf("Errore nell'inizializzazione di pNil.\n");
}
}

Tree *NewNode(int numero)
{
Tree *r;

r = (Tree *)malloc(sizeof(Tree));

if( !r )
{
printf("Memoria insufficiente.\n");
return pNil;
}

r->numero = numero;
r->pos = 0;
r->count = 1;
r->color = 'b'; // 'b' = Black; 'r' = Red
r->father = pNil;
r->left = pNil;
r->right = pNil;

return r;
}

Tree *InsertNode(Tree *node, int numero, int pos)
{
int nRes;
Tree *z = pNil;
Tree *y = pNil;
Tree *pRadice = pNil;

z = NewNode(numero);
if ( z == pNil )
return pNil;

pRadice = node;

while ( pRadice != pNil )
{
y = pRadice;

if ( z->numero < pRadice->numero )
nRes = -1;
else if ( z->numero > pRadice->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
pRadice = pRadice->left;
}
else if ( nRes > 0 )
{
pRadice = pRadice->right;
}
else
{
pRadice->count++;
return node;
}
}

z->pos = pos;
z->father = y;
if ( y == pNil )
{
node = z;
}
else
{
if ( z->numero < y->numero )
nRes = -1;
else if ( z->numero > y->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
y->left = z;
}
else if ( nRes > 0 )
{
y->right = z;
}
else // Trovato
{
y->count++;
return node;
}
}

z->left = pNil;
z->right = pNil;
z->color = 'r'; // Red

InsertFixup(&node, &z);

return node;
}

void InsertFixup(Tree **head, Tree **z)
{
Tree *y = pNil;

while ( (*z)->father->color == 'r' )
{
if ( (*z)->father == (*z)->father->father->left )
{
y = (*z)->father->father->right;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->right )
{
*z = (*z)->father;
*head = TreeRotateLeft(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateRight(*head, (*z)->father->father);
}
}
else
{
y = (*z)->father->father->left;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->left )
{
*z = (*z)->father;
*head = TreeRotateRight(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateLeft(*head, (*z)->father->father);
}
}
}

(*head)->color = 'b';
}

Tree *TreeRotateLeft(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->right == pNil )
return head;

y = node->right;
node->right = y->left;

if ( y->left != pNil )
{
y->left->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->left )
{
node->father->left = y;
}
else
{
node->father->right = y;
}
}

y->left = node;
node->father = y;

return head;
}

Tree *TreeRotateRight(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->left == pNil )
return head;

y = node->left;
node->left = y->right;

if ( y->right != pNil )
{
y->right->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->right )
{
node->father->right = y;
}
else
{
node->father->left = y;
}
}

y->right = node;
node->father = y;

return head;
}

void FreeTree(Tree *head)
{
Tree *temp1, *temp2;

Tree *stack[MAX_STACK];
int top;

top = 0;

if ( head == pNil )
return;

temp1 = temp2 = head;

while ( temp1 != pNil )
{
for(; temp1->left != pNil; temp1 = temp1->left)
stack[top++] = temp1;

while ( (temp1 != pNil) && (temp1->right == pNil || temp1->right == temp2) )
{
temp2 = temp1;
free(temp2);
if ( top == 0 )
return;
temp1 = stack[--top];
}

stack[top++] = temp1;
temp1 = temp1->right;
}
}

Stati DFA(char *szFileName, int *pArray)
{
Stati stato = S0;
FILE *fp;
char *buffer;
unsigned char c;
int numread = 0;
int k = 0;

int riga;
int num;
int num_righe;
int ultimo_blocco;

errno_t ferr;

riga = 0;
num_righe = 0;

ferr = fopen_s(&fp, szFileName, "rb");
if ( ferr != 0 )
{
printf("Errore nell'apertura del file %s\n", szFileName);
return S_ERROR_OPEN_FILE;
}

buffer = (char*)malloc(sizeof(char)*BUFFER_SIZE + 1);
if ( !buffer )
{
printf("Errore nell'allocazione della memoria.");
fclose(fp);
return -1;
}

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread <= 0 )
{
printf("Il file e' vuoto.\n");
return -1;
}
*(buffer + numread + 1) = '\0';
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

printf("");

k = 0;
while ( *(buffer + k++) != '\n' )
;

num = 0;
while ( 1 )
{
c = *(buffer + k++);
if ( c == EOF )
break;

if ( c == '\0' )
{
k = 0;
if ( ultimo_blocco )
break;

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

*(buffer + numread + 1) = '\0';

c = *(buffer + k++);
}

switch (stato)
{
case S0:
num = 0;
if ( c >= '0' && c <= '9' )
{
num = c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
stato = S0;
}
else
{
printf("\nErrore in S0 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;

case S1:
if ( c >= '0' && c <= '9' )
{
num = num * 10 + c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
*(pArray + riga) = num;
riga++;
//*pTree = InsertNode(*pTree, num, riga);
num = 0;
stato = S0;
}
else
{
printf("\nErrore in S1 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;
}
}

free(buffer);

if ( fp )
fclose(fp);

return stato;
}

void Search(Tree *head, Tree **result, int key)
{
Tree *node;

*result = pNil;
node = head;

if ( head == pNil )
return;

while( 1 )
{
if ( key < node->numero )
{
if ( node->left == pNil )
break;
node = node->left;
}
else if ( key > node->numero )
{
if ( node->right == pNil )
break;
node = node->right;
}
else // key == node->data
{
*result = node;
break;
}
}
}

void TreeMinimum(Tree *head, Tree **result)
{
Tree *nodo = head;

*result = pNil;

if ( nodo == pNil )
return;

*result = nodo;

while ( nodo != pNil )
{
*result = nodo;
nodo = nodo->left;
}
}

int ReverseInOrder(Tree *head, int somma)
{
int diff;

Tree *temp;
Tree *findTree = pNil;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return 0;

temp = head;

while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->right;
}
else
{
printf("Errore: lo stack e' pieno.\n");
return 0;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

diff = somma - temp->numero;
if ( diff < 0 )
return 0;

Search(head, &findTree, diff);
if ( findTree != pNil && temp != pNil )
return 1;

temp = temp->left;
}
else
{
break;
}
}
}

return 0;
}

int main()
{
int a[100000];

Stati stato;
Tree *p = NULL;
Tree *pmin = NULL;

DWORD ms1, ms2;

int k;
int diff;

InitNil(&pNil);

p = pNil;
pmin = pNil;

stato = DFA("C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista\\lista.txt", a);

ms1 = GetTickCount();

for( k = 0; k < 100000; k++ )
{
p = InsertNode(p, *(a+k), k);
}

if( stato == S0 || stato == S1 )
{
TreeMinimum(p, &pmin);
k = pmin->numero;

while ( 1 )
{
diff = 19999999 - k++;

if ( !ReverseInOrder(p, diff) )
break;
}

ms2 = GetTickCount();

printf("\nIl numero piu' grande, minore di venti milioni\n");
printf("tale che non sia la somma di due valori\n");
printf("qualsiasi della lista e' -> %d\n\n", diff);

printf("\nTime -> %dms\n", ms2 - ms1);
}
else
{
printf("\nL'automa ha restituito un errore.\n");
return -1;
}

return 0;
}

cionci
25-07-2008, 11:31
Punto A in C:

#include <stdio.h>
#include <stdlib.h>

#define LIMIT 2
#define MAX_NUMBER 11000000

int main()
{
FILE *f;
int numberCount, i;
unsigned int *numbers;
int overLimitCounter = 0;
int maxRepeat = 1;
int valueRead;

if(!(f = fopen("lista.txt", "r")))
return -1;

fscanf(f, "//%d//", &numberCount);

numbers = (unsigned int *) malloc(sizeof(unsigned int) * MAX_NUMBER);

for(i = 0; i < numberCount; ++i)
{
fscanf(f, "%d", &valueRead);
numbers[valueRead]++;
if(numbers[valueRead] == LIMIT)
{
overLimitCounter++;
}
if(numbers[valueRead] > maxRepeat)
{
maxRepeat = numbers[valueRead];
}
}

fclose(f);

printf("%d numbers are repeated at least %d times. Most frequent number is repeated %d times.\n", overLimitCounter, LIMIT, maxRepeat);
return 0;
}

~$ time ./contest
459 numbers are repeated at least 2 times. Most frequent number is repeated 4 times.

real 0m0.064s
user 0m0.032s
sys 0m0.032s

Ovviamente viene considerato il programma per intero ;) Quindi compresa lettura da file.
Se il vettore lo creo di unsigned char il totale passa a 41 ms.

rеpne scasb
26-07-2008, 21:24
Tanto per rimanere allenata, propongo la mia versione in linguaggio C:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <mem.h>

#define LEN_INPUT_LINE 32
#define N_CLK 10
#define ITEMS_SIZE 5 * sizeof(long)
#define N_VAL 5
#define SEARCH_LIMIT 19999999
#define INPUT_FILE_NAME "LISTA.TXT"

long * Bin2Nor(long *,long *);
int Search_Val(long,long *,long *,long *,long *,long *,long);
void Search_Non_Val(long,long,long *,long,char *);

int main()

{
clock_t clk[N_CLK];
FILE *input_file;
char *input_line,*t_point;
long n_element,*t_bin,*t_exa,*t_bin_tmp,*s_bin,n_rip,max_rip,i,j,k,l,pos1,pos2,sum1,sum2,input_val[N_VAL]={217660,222940,9999999,11155123,18185748};

clk[0]=clock();

if((input_line=malloc(LEN_INPUT_LINE*sizeof(char)))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

if((input_file=fopen(INPUT_FILE_NAME,"r"))==NULL)
{
fprintf(stderr,"Non trovo il file " INPUT_FILE_NAME "\n");
return 1;
}

fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}

if((input_line[0]!='/')||(input_line[1]!='/')||(input_line[strlen(input_line)-2]!='/')||(input_line[strlen(input_line)-3]!='/'))
{
fprintf(stderr,"Formato irregolare");
return 1;
}

input_line[strlen(input_line)-3]=0;
n_element=atol(input_line+2);

if((t_bin=malloc(n_element*ITEMS_SIZE))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

t_bin_tmp=t_bin;
fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}
input_line[strlen(input_line)-1]=0;
*t_bin=atol(input_line);
*(t_bin+1)=*(t_bin+2)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_SIZE>>2;

for(l=k=i=1;i<n_element;i++)
{
fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}
input_line[strlen(input_line)-1]=0;
j=atol(input_line);
t_exa=t_bin_tmp;
do
{
if(j<*t_exa)
{
if(*(t_exa+3)==NULL)
{
*(t_exa+3)=(long)t_bin;
*t_bin=j;
*(t_bin+2)=l;
*(t_bin+1)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_SIZE>>2;
j=-1;
k++;
l++;
}
else
t_exa=(long *)*(t_exa+3);
}
else
{
if(j>*t_exa)
{
if(*(t_exa+4)==NULL)
{
*(t_exa+4)=(long)t_bin;
*t_bin=j;
*(t_bin+2)=l;
*(t_bin+1)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_SIZE>>2;
j=-1;
k++;
l++;
}
else
t_exa=(long *)*(t_exa+4);
}
else
{
(*(t_exa+1))++;
l++;
j=-1;
}
}
} while (j!=-1);
}
t_bin=t_bin_tmp;

fclose(input_file);

clk[1]=clock();
printf("*** Tempo per creazione albero binario: %7.3f secondi\n",(double)(clk[1]-clk[0])/CLK_TCK);

for(max_rip=n_rip=i=0;i<k;i++,t_bin+=ITEMS_SIZE>>2)
{
if(*(t_bin+1))
{
n_rip++;
if(*(t_bin+1)>max_rip)
max_rip=*(t_bin+1);
}
}
t_bin=t_bin_tmp;

clk[2]=clock();
printf("\nNumero di elementi con almeno 2 ripetizioni: %d\n",n_rip);
printf("Massimo numero di ripetizioni: %d\n",max_rip+1);
printf("\n*** Tempo per soluzione quesito A-Base: %7.3f secondi\n",(double)(clk[2]-clk[1])/CLK_TCK);

if((s_bin=malloc(k*ITEMS_SIZE))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

Bin2Nor(t_bin,s_bin);

free(t_bin);

clk[3]=clock();
printf("*** Tempo per alterazione albero binario: %7.3f secondi\n\n",(double)(clk[3]-clk[2])/CLK_TCK);

for(i=0;i<N_VAL;i++)
{
if(Search_Val(input_val[i],&pos1,&pos2,&sum1,&sum2,s_bin,k))
printf("Valore %d=%d+%d (posizioni: %d,%d)\n",input_val[i],sum1,sum2,pos1,pos2);
else
printf("Valore somma %d non trovato\n",input_val[i]);
}

clk[4]=clock();
printf("\n*** Tempo per soluzione quesito B-Avanzato: %7.3f secondi\n",(double)(clk[4]-clk[3])/CLK_TCK);

if((t_point=calloc(n_element<<1,sizeof(char)))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

Search_Non_Val(SEARCH_LIMIT,n_element<<1,s_bin,k,t_point);

clk[5]=clock();

printf("\n*** Tempo per soluzione quesito C-Esperto: %7.3f secondi\n",(double)(clk[5]-clk[4])/CLK_TCK);
printf("\n*** Tempo totale per l'intera soluzione: %7.3f secondi\n",(double)(clk[5]-clk[0])/CLK_TCK);

free(t_point);
free(input_line);
free(s_bin);
return 0;
}

long * Bin2Nor(long *sg,long *dt)

{
if(sg!=NULL)
{
dt=Bin2Nor((long *)*(sg+3),dt);
memcpy(dt,sg,ITEMS_SIZE);
dt+=ITEMS_SIZE>>2;
dt=Bin2Nor((long *)*(sg+4),dt);
}
return(dt);
}

int Search_Val(long input_val,long *pos1,long *pos2,long *sum1,long *sum2,long *s_bin,long k)

{
int i0,i1,im,i;

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*(ITEMS_SIZE>>2));
if(i>input_val)
i1=im;
else
i0=im;
} while ((i1-i0)>1);

if(*(s_bin+i1*(ITEMS_SIZE>>2))<input_val)
i0=i1;

i1=0;
do
{
i=*(s_bin+i0*(ITEMS_SIZE>>2))+*(s_bin+i1*(ITEMS_SIZE>>2));
if(i==input_val)
{
*sum1=*(s_bin+i1*(ITEMS_SIZE>>2));
*sum2=*(s_bin+i0*(ITEMS_SIZE>>2));
*pos1=*(s_bin+i1*(ITEMS_SIZE>>2)+2);
*pos2=*(s_bin+i0*(ITEMS_SIZE>>2)+2);
return 1;
}
i=i1;
i1++;
if((*(s_bin+i0*(ITEMS_SIZE>>2))+*(s_bin+i1*(ITEMS_SIZE>>2)))>input_val)
{
i1=0;
i0--;
}
} while (i<i0);

return 0;
}

void Search_Non_Val(long input_val,long range,long *s_bin,long k,char *t_point)

{
int i0,i1,im,i,j,max,min;

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*(ITEMS_SIZE>>2));
if(i>input_val)
i1=im;
else
i0=im;
} while ((i1-i0)>1);

if(*(s_bin+i1*(ITEMS_SIZE>>2))<input_val)
i0=i1;
max=i0;

min=input_val-*(s_bin+i0*(ITEMS_SIZE>>2));

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*(ITEMS_SIZE>>2));
if(i>min)
i1=im;
else
i0=im;
} while ((i1-i0)>1);
min=i0;

i1=min;
i0=max;
do
{
i=*(s_bin+i0*(ITEMS_SIZE>>2))+*(s_bin+i1*(ITEMS_SIZE>>2));
j=i1;
if(i>input_val)
{
i1=min;
i0--;
}
else
{
i1++;
t_point[input_val-i]=1;
}
} while (*(s_bin+i0*(ITEMS_SIZE>>2))+*(s_bin+i1*(ITEMS_SIZE>>2))>(input_val-range));

for(i=0;i<range;i++)
{
if(t_point[i]==0)
{
printf("\nIl valore %d non costituisce la somma di alcuna coppia di elementi\n",input_val-i);
break;
}
}
}


Questo e' un tipico output:


*** Tempo per creazione albero binario: 0.031 secondi

Numero di elementi con almeno 2 ripetizioni: 459
Massimo numero di ripetizioni: 4

*** Tempo per soluzione quesito A-Base: 0.000 secondi
*** Tempo per alterazione albero binario: 0.016 secondi

Valore somma 217660 non trovato
Valore somma 222940 non trovato
Valore 9999999=7895+9992104 (posizioni: 3590,37312)
Valore 11155123=1078115+10077008 (posizioni: 38441,92416)
Valore 18185748=8099248+10086500 (posizioni: 64082,60049)

*** Tempo per soluzione quesito B-Avanzato: 0.031 secondi

Il valore 19991308 non costituisce la somma di alcuna coppia di elementi

*** Tempo per soluzione quesito C-Esperto: 0.000 secondi

*** Tempo totale per l'intera soluzione: 0.078 secondi


Spero sia utile per scopi didattici e tempo permettendo sono disponibile a discuterne l'algoritmo (in special-modo per la parte C, che presenta una minima difficolta'). Un accenno sui tempo di sviluppo:


Tempo di sviluppo: 1 ora e mezza circa
Bugs scoperti dopo la prima stesura: 2
Tempo di risoluzione bugs: 10 minuti scarsi
Ottimizzazione: nessuna


Per ora non vedo bugs, ma potrebbero essercene. Nel caso qualcuno ne trovi, e' gradito un avvertimento.

rеpne scasb
26-07-2008, 21:48
Poiche' la lista di soli 100.000 elementi, non mi pare sufficiente per poter verificare i tempi di esecuzione, in quanto troppo piccoli per essere misurati, ho preparato una lista da 2.000.000 di elementi. Tale lista e' anche utile per definire la complessita' di ogni 'fase' in funzione della quantità (tempi di esecuzione)/(numero di elementi). Tale lista e' raggiungibile presso: http://www.usaupload.net/d/lfh1u30b08k

Questo e' un mio tipico output con 2.000.000 di elementi:


*** Tempo per creazione albero binario: 1.547 secondi

Numero di elementi con almeno 2 ripetizioni: 3674
Massimo numero di ripetizioni: 3

*** Tempo per soluzione quesito A-Base: 0.000 secondi
*** Tempo per alterazione albero binario: 0.219 secondi

Valore 217660=4289+213371 (posizioni: 633927,1468926)
Valore 222940=3081+219859 (posizioni: 437213,983730)
Valore 9999999=5596+9994403 (posizioni: 1145140,1859118)
Valore 11155123=6697+11148426 (posizioni: 55425,1547830)
Valore 18185748=8656+18177092 (posizioni: 1665,5117)

*** Tempo per soluzione quesito B-Avanzato: 0.000 secondi

Il valore 16075394 non costituisce la somma di alcuna coppia di elementi

*** Tempo per soluzione quesito C-Esperto: 2.843 secondi

*** Tempo totale per l'intera soluzione: 4.609 secondi

shinya
26-07-2008, 22:20
Ma questo contest si è trasformato in una specie di Obfuscated C Code Contest?? :p

marco.r
26-07-2008, 23:15
Per ora non vedo bugs, ma potrebbero essercene. Nel caso qualcuno ne trovi, e' gradito un avvertimento.

Stavo provando per curiosita' a far andare il tuo programma, ma mi crasha durante la lettura del file, attorno alla linea 80 ( j=atol(input_line); ), quando si trova piu' o meno a meta' del file ( riga 1000993 , valore 155832651 ).
Puo' dipendere da uno dei seguenti fattori ?
- Ho convertito il file in formato UNIX
- Eseguo sotto linux a 64bit
- Ho definito CLK_TCK come CLOCKS_PER_SEC perche' non definito nel mio sistema.

rеpne scasb
26-07-2008, 23:27
- Ho convertito il file in formato UNIX

E' questo. Oppure la funziona 'fgets' sotto unix, non funziona nello stesso modo di Windows.

Mi correggo ancora: il problema potrebbe essere connesso ai 64-bit, infatti hai un errore intorno ad 1000000 di elementi univoci letti (ossia 1000993 letture non univoche); probabilmento il software sta allocando meta' della memoria necessaria, oppure un long e' grande 64-bit.

marco.r
26-07-2008, 23:50
Anche lasciando il file in formato dos (e cambiando il controllo sulla prima riga), il problema permane. Stranamente sembra che quella riga per qualche motivo non venga terminata con \0, a differenza della milionata che viene prima :confused:.

Provando con valgrind mi viene segnalato ad un certo una "invalid write of size 8" in questo pezzo di codice (circa linea 111)

if(*(t_exa+4)==NULL)
{
*(t_exa+4)=(long)t_bin;
*t_bin=j; // <------------ QUI
*(t_bin+2)=l;
*(t_bin+1)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_SIZE>>2;
j=-1;
k++;
l++;
}

Non ho ancora capito il tuo codice :D, per cui non posso essere molto piu' di aiuto.

marco.r
26-07-2008, 23:52
E' questo. Oppure la funziona 'fgets' sotto unix, non funziona nello stesso modo di Windows.

Mi correggo ancora: il problema potrebbe essere connesso ai 64-bit, infatti hai un errore intorno ad 1000000 di elementi univoci letti (ossia 1000993 letture non univoche); probabilmento il software sta allocando meta' della memoria necessaria, oppure un long e' grande 64-bit.
Si', i miei long sono di 64bit

rеpne scasb
27-07-2008, 07:40
Si', i miei long sono di 64bit

E' questo il problema. Ho rimaneggiato il codice, per renderlo piu' trasportabile:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <mem.h>

#define LEN_INPUT_LINE 32
#define N_CLK 10
#define ITEMS_SIZE 5 * sizeof(long)
#define ITEMS_ARGS (ITEMS_SIZE/sizeof(long))
#define N_VAL 5
#define SEARCH_LIMIT 19999999
#define INPUT_FILE_NAME "LISTA.TXT"

long * Bin2Nor(long *,long *);
int Search_Val(long,long *,long *,long *,long *,long *,long);
void Search_Non_Val(long,long,long *,long,char *);

int main()

{
clock_t clk[N_CLK];
FILE *input_file;
char *input_line,*t_point;
long n_element,*t_bin,*t_exa,*t_bin_tmp,*s_bin,n_rip,max_rip,i,j,k,l,pos1,pos2,sum1,sum2,input_val[N_VAL]={217660,222940,9999999,11155123,18185748};

clk[0]=clock();

if((input_line=malloc(LEN_INPUT_LINE*sizeof(char)))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

if((input_file=fopen(INPUT_FILE_NAME,"r"))==NULL)
{
fprintf(stderr,"Non trovo il file " INPUT_FILE_NAME "\n");
return 1;
}

fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}

if((input_line[0]!='/')||(input_line[1]!='/')||(input_line[strlen(input_line)-2]!='/')||(input_line[strlen(input_line)-3]!='/'))
{
fprintf(stderr,"Formato irregolare");
return 1;
}

input_line[strlen(input_line)-3]=0;
n_element=atol(input_line+2);

if((t_bin=malloc(n_element*ITEMS_SIZE))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

t_bin_tmp=t_bin;
fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}
input_line[strlen(input_line)-1]=0;
*t_bin=atol(input_line);
*(t_bin+1)=*(t_bin+2)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_ARGS;

for(l=k=i=1;i<n_element;i++)
{
fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}
input_line[strlen(input_line)-1]=0;
j=atol(input_line);
t_exa=t_bin_tmp;
do
{
if(j<*t_exa)
{
if(*(t_exa+3)==NULL)
{
*(t_exa+3)=(long)t_bin;
*t_bin=j;
*(t_bin+2)=l;
*(t_bin+1)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_ARGS;
j=-1;
k++;
l++;
}
else
t_exa=(long *)*(t_exa+3);
}
else
{
if(j>*t_exa)
{
if(*(t_exa+4)==NULL)
{
*(t_exa+4)=(long)t_bin;
*t_bin=j;
*(t_bin+2)=l;
*(t_bin+1)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_ARGS;
j=-1;
k++;
l++;
}
else
t_exa=(long *)*(t_exa+4);
}
else
{
(*(t_exa+1))++;
l++;
j=-1;
}
}
} while (j!=-1);
}
t_bin=t_bin_tmp;

fclose(input_file);

clk[1]=clock();
printf("*** Tempo per creazione albero binario: %7.3f secondi\n",(double)(clk[1]-clk[0])/CLK_TCK);

for(max_rip=n_rip=i=0;i<k;i++,t_bin+=ITEMS_ARGS)
{
if(*(t_bin+1))
{
n_rip++;
if(*(t_bin+1)>max_rip)
max_rip=*(t_bin+1);
}
}
t_bin=t_bin_tmp;

clk[2]=clock();
printf("\nNumero di elementi con almeno 2 ripetizioni: %d\n",n_rip);
printf("Massimo numero di ripetizioni: %d\n",max_rip+1);
printf("\n*** Tempo per soluzione quesito A-Base: %7.3f secondi\n",(double)(clk[2]-clk[1])/CLK_TCK);

if((s_bin=malloc(k*ITEMS_SIZE))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

Bin2Nor(t_bin,s_bin);

free(t_bin);

clk[3]=clock();
printf("*** Tempo per alterazione albero binario: %7.3f secondi\n\n",(double)(clk[3]-clk[2])/CLK_TCK);

for(i=0;i<N_VAL;i++)
{
if(Search_Val(input_val[i],&pos1,&pos2,&sum1,&sum2,s_bin,k))
printf("Valore %d=%d+%d (posizioni: %d,%d)\n",input_val[i],sum1,sum2,pos1,pos2);
else
printf("Valore somma %d non trovato\n",input_val[i]);
}

clk[4]=clock();
printf("\n*** Tempo per soluzione quesito B-Avanzato: %7.3f secondi\n",(double)(clk[4]-clk[3])/CLK_TCK);

if((t_point=calloc(n_element<<1,sizeof(char)))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

Search_Non_Val(SEARCH_LIMIT,n_element<<1,s_bin,k,t_point);

clk[5]=clock();

printf("\n*** Tempo per soluzione quesito C-Esperto: %7.3f secondi\n",(double)(clk[5]-clk[4])/CLK_TCK);
printf("\n*** Tempo totale per l'intera soluzione: %7.3f secondi\n",(double)(clk[5]-clk[0])/CLK_TCK);

free(t_point);
free(input_line);
free(s_bin);
return 0;
}

long * Bin2Nor(long *sg,long *dt)

{
if(sg!=NULL)
{
dt=Bin2Nor((long *)*(sg+3),dt);
memcpy(dt,sg,ITEMS_SIZE);
dt+=ITEMS_ARGS;
dt=Bin2Nor((long *)*(sg+4),dt);
}
return(dt);
}

int Search_Val(long input_val,long *pos1,long *pos2,long *sum1,long *sum2,long *s_bin,long k)

{
int i0,i1,im,i;

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*ITEMS_ARGS);
if(i>input_val)
i1=im;
else
i0=im;
} while ((i1-i0)>1);

if(*(s_bin+i1*ITEMS_ARGS)<input_val)
i0=i1;

i1=0;
do
{
i=*(s_bin+i0*ITEMS_ARGS)+*(s_bin+i1*ITEMS_ARGS);
if(i==input_val)
{
*sum1=*(s_bin+i1*ITEMS_ARGS);
*sum2=*(s_bin+i0*ITEMS_ARGS);
*pos1=*(s_bin+i1*ITEMS_ARGS+2);
*pos2=*(s_bin+i0*ITEMS_ARGS+2);
return 1;
}
i=i1;
i1++;
if((*(s_bin+i0*ITEMS_ARGS)+*(s_bin+i1*ITEMS_ARGS))>input_val)
{
i1=0;
i0--;
}
} while (i<i0);

return 0;
}

void Search_Non_Val(long input_val,long range,long *s_bin,long k,char *t_point)

{
int i0,i1,im,i,j,max,min;

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*ITEMS_ARGS);
if(i>input_val)
i1=im;
else
i0=im;
} while ((i1-i0)>1);

if(*(s_bin+i1*ITEMS_ARGS)<input_val)
i0=i1;
max=i0;

min=input_val-*(s_bin+i0*ITEMS_ARGS);

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*ITEMS_ARGS);
if(i>min)
i1=im;
else
i0=im;
} while ((i1-i0)>1);
min=i0;

i1=min;
i0=max;
do
{
i=*(s_bin+i0*ITEMS_ARGS)+*(s_bin+i1*ITEMS_ARGS);
j=i1;
if(i>input_val)
{
i1=min;
i0--;
}
else
{
i1++;
t_point[input_val-i]=1;
}
} while (*(s_bin+i0*ITEMS_ARGS)+*(s_bin+i1*(ITEMS_ARGS))>(input_val-range));

for(i=0;i<range;i++)
{
if(t_point[i]==0)
{
printf("\nIl valore %d non costituisce la somma di alcuna coppia di elementi\n",input_val-i);
break;
}
}
}


Non ho un sistema operativo a 64-bit, quindi non posso testarlo. "Dovrebbe" funzionare. Considera che cosi' utilzzera il doppio della ram normalmente utilizzata, aspettati quindi un discreto decremento delle prestazioni rispetto alla stessa versione compilata sulla tua macchina su un sistema operativo a 32-bit.

Allego l'eseguibile Win32 per chi vuol fare dei test. Magari qualche "anima pia", potrebbe anche tracciare un grafico Elementi/Tempo di esecuzione, cosi' da avere una valutazione approssimata delle complessita'.

rеpne scasb
27-07-2008, 09:26
Ma questo contest si è trasformato in una specie di Obfuscated C Code Contest?? :p

Se volevo offuscare qualcosa scrivevo una cosa simile a questa: :p


[.]>+<+[>>>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[-]+<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<+
>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]+<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<
+>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>
>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<
<<<+>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>
>>>>>>>>>>>>>[-]+>>>[-]<<<[>>>+<<<-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>
>>>>>>>>>>>>>>>>>>>>>>>[-]+>>[-]<<[>>+<<-]>>>[>>[-]<<-[>>+<<-]+>>]>[-]<<
<[<<]>[>[>>]>+<<<[<<]>-]>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>
>>>>>>>>>>>>>>>>[-]++>>>[-]<<<[>>>+<<<-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>
>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+>>[-]<<[>>+<<-]>>>[>>[-]<<-[>>+<<-]+>>]>[
-]<<<[<<]>[>[>>]>+<<<[<<]>-]>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>
>>>>>>>>>>>>>>>>>>>>[-]+++>>>[-]<<<[>>>+<<<-]<<<<<<<<<<<<<<<<<<<<<<<<<<<
<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]>>[-]<<[>>+<<-]>>>[>>[-]<<-[>>+<<-]+>
>]>[-]<<<[<<]>[>[>>]>+<<<[<<]>-]>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>
>>>>>>>>>>>>>>>>>>>>>>>>[-]++++>>>[-]<<<[>>>+<<<-]<<<<<<<<<<<<<<<<<<<<<<
<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++>>[-]<<[>>+<<-]>>>[>>[-]<<-[
>>+<<-]+>>]>[-]<<<[<<]>[>[>>]>+<<<[<<]>-]>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++<[-]>[<+>-]<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[-]]>>[-]>[-]+<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[
>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[
-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<
<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>
-]<<<<<<<<[>>>>>>>>+<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>
>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<
<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<
<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>
>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>
>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]++>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>
>-]<[>++++++++++.[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<[>>
>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>
>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<
<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->
>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>
>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>
>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]+++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>+++
++++++++[>++++++++>++++++++++>+++>+++++++++<<<<-]>+.>+.++++++.>-.>--.<<-
--.>>++++.<.>+++.<<---.---.>>----.<<---.+++++.>>+++.<.>[-]<[-]<[-]<[-]<<
[-]]>>[-]>[-]+++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]
<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]
<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<
<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<
<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]+<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>
>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<
<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<
<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>
>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>
>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]++++>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>
>-]<[>++++++++++++++++[>++++++>+++++++>++>++++++>+++<<<<<-]>-------.>-.+
+++++.>.>+.<<---.>>++++.<.>++++.<<----.>.<<++++++++.>>.<+++++.>>++++.<<<
.>>>-..<.<-.---..>>+.>--.[-]<[-]<[-]<[-]<[-]<++++++++++.[-]++++++++++.[-
]+++++++++++++++++[>+++++>++++++>+++++++>++>+++<<<<<-]>-.>++.---.>-----.
<.>>--.<<++++.>+.>.<<--------.>-----.>.<<++++.>++++++++++.<++++.>----.>.
<<----.----.>-.+.>>-----.[-]<[-]<[-]<[-]<[-]<++++++++++.[-]<[-]]>>[-]>[-
]++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-
<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<
<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<[>>>>>>
>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>
>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[
-]++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>
>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<
<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>
>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>
>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]+++++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>+++
+++++++++++++[>++++++>+++++++>++>++++++>+++<<<<<-]>-------.>-.++++++.>.>
+.<<---.>>++++.<.>++++.<<----.>.<<++++++++.>>.<<+++.---.>++++.>>++.<.<--
.<.>+++..<.>>>----.--.>--.[-]<[-]<[-]<[-]<[-]<++++++++++.[-]++++++++++.[
-]+++++++++++++++++[>+++++>++++++>+++++++>++>+++<<<<<-]>-.>++.---.>-----
.<.>>--.<<----.>.<++++.>>.<<.>++++++.<++++.>----.-.>.<<----.----.>.+.>.<
<.>------.<+++.>>.<+++++++++.<+.>----.+.>>-----.[-]<[-]<[-]<[-]<[-]<++++
++++++.[-]<[-]]>>[-]>[-]+++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->
>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<
-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<
<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>
>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>[-]+++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<
<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>
>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<
<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<
<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>
>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]++++++>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]
<[>+>+<<-]>>[<<+>>-]<[>++++++++++++++++[>++++++>+++++++>++>++++++>+++<<<
<<-]>-------.>-.++++++.>.>+.<<---.>>++++.<.>++++.<<----.>.<++++++.>>-.--
-.<.<-------.++.++++++.-.>>+++.<.<-----.>>--.<.>-----.<.<++++.------.>>.
<<-..>.>++.--.<<++++++++++.>>++++.>--.[-]<[-]<[-]<[-]<[-]<++++++++++.[-]
++++++++++.[-]+++++++++++++++++[>+++++>++++++>+++++++>++>+++<<<<<-]>-.>+
+.---.>-----.<.>>--.<<----.>.<++++.>>.<<.>++++++.<++++.>----.-.>.<<----.
----.>.+.>.<<.>------.<+++.>>.<+++++++.-----.>>-----.[-]<[-]<[-]<[-]<[-]
<++++++++++.[-]<[-]]>>[-]>[-]++++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>
>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>
[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>[-]<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+
>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<
<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>
>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[
<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<
<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<
<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]+++
++++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]
>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>++++++++++++++++[>++++++>+++++++>++>+++++
+>+++<<<<<-]>-------.>-.++++++.>.>+.<<---.>>++++.<.<---.++++++.-.-.>>+++
+.-----.+.<.>----.<.<.------.>>.<<-..>.>++.--.<<++++++++++.>>++++.>--.[-
]<[-]<[-]<[-]<[-]<++++++++++.[-]++++++++++.[-]+++++++++++++++++[>+++++>+
+++++>+++++++>++>+++<<<<<-]>-.>++.---.>-----.<.>>--.<<++++.>+.>.<<------
--.>-----.>.<<++++.>++++++++++.<++++.>----.>.<<-----.>-----.++++++++.---
------.>>-----.[-]<[-]<[-]<[-]<[-]<++++++++++.[-]<[-]]>>[-]>[-]+++++++<[
-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]
>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<
<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>
>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<
<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<
<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>-]>
>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<+>+<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<-]>>[>>[<+<<<+>>>>-]<<<<[>>>>+<<<<-]+>>>[<<->>>-<<<<->>>[-]]<<<[>>[
-]+<<-]>>-]>>[>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<[-]]<<<[-
]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>
>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>
>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<[-]<[-]++++++++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>++++++++
++.[-]<[-]]>>[-]>[-]++++++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>
-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-
]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-
]+<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>
>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>[-]>[-]+++++++++<[-]<[-]<<[>>>+<
+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>
>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>+<<<<<<<<<<
<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>-]<<<<<<<<<<<[>>>>>>>>>>>+<<<<<<<<<<<-][-]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++<<<<<<<<<<<<<
<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>-]>>>>>>>>>
>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+<<
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>
>[>>[<+<<<+>>>>-]<<<<[>>>>+<<<<-]+>>>[<<->>>-<<<<->>>[-]]<<<[>>[-]+<<-]>
>-]>>[>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<[-]]<<<[-]>>>>>>>
>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]++++++++++>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]
<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<[
>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>-]<<<<<<<<<<<[
>>>>>>>>>>>+<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<[>>>+<<<-]
>>>[>>[-]<<-[>>+<<-]+>>]>[<<<[<<]>+>[>>]>-]<<<[<<]>[<<+<<<<<<<<<<<<<<<<<
<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>[>>]>[-]<<<[<<]>[>[>>]>+<<<[<<]>-]>->>>>>>>>>>>
>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>
>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>
>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>
>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<
<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<[-]<[-]+++++++++++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<
<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<[<<<<
<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]>>>>>>>>>>>>>>>>>>>
>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>
>>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>
>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<
<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<
<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<
[-]++++++++++++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>+++++++++++[>++++++++>++++++++
++>+++>+++++++++<<<<-]>+.>+.++++++.>-.>.--.<<-------.>.<+++++.>>++++..<.
>----.<<-----.>.<+.>>+.<<-----.>>+++.--.<<++++++++++.>.>[-]<[-]<[-]<[-]<
<[-]]>>[-]>[-]++++++++++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]
<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>
>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<
<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>
-]<<<<<<<<<<<[>>>>>>>>>>>+<<<<<<<<<<<-]>[-]>[-]>[-]>[-]>>>>>>>>>>>>>>>>>
>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<+[>+<<<<+>>>-]<<<[>>>+<<<-]+>>>>-------
---[<<<<->>>>[-]]<<<<[>>+>[-]<<<-]>>[>>+<<<<+>>-]<<[>>+<<-]+>>>>--------
--[<<<<->>>>[-]]<<<<[>+>[-]<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<
<<<<<<<<<<<<<<<<[<++++++++[>++++++>++++++<<-]>.>.[-]<[-]]>[<<++++++++[>>
++++++<<-]>>.[-]]<<++++++++[>>>++++++<<<-]>>>.[-]<<<++++++++++.[-]<[-]]>
>[-]>[-]+++++++++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<
[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<
[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<
<<<<<<[>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>-]<<<<<
<<<<<<[>>>>>>>>>>>+<<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>[-]+[<<<<<<<<<<<<<<<<<<<<<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<
<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]
>>>>>>>>>>>[-]>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>-]<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]+++++++++>>[-]]>>[-]>[-]++++++++++<[-]
<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>
>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+
>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>
>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<
<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<
<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>
>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<-
>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>
>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<[-]<[-]+++++++++++++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-
]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>[-]>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<
<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>[-]>>>>>>>>>>>>>>>>>>[<<<<
<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>
>>>>>>>>>>>>>>>>>>>>>>[-]>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<
<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<-]<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<[-]]>>[-]>[-]+++++++++++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>
-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<
<[-]+>>>[-]]<<-]>>>[-]<[-]>[-]++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<
<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]
]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>
>>[-]+<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<+++++++[>+++++++++<-]>-
.[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>,<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>
>[<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
[-]]>>[-]>[-]++++++++++++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-
]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]
>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>,<<[-]
>>[<<+>>-][-]<<[>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>
>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<
<<<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]
++++++++++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>
>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<
<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<
<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<
<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<-][-
]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++++++++++<
<[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>
>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>
>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<
<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>>>>>
>>>>>>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>>>>>
>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<
<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<
<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[
-]<[-]++++++++++++++>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>[-]<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<
<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<[-]++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>
>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<
<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<
<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[
-]++++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+++++++++
+++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<
<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<
<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]-<<<<<<<<<<<
<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<
<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>
>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]<[-]+++++++++++++++>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>
+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<
<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-][-]
<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>
>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>[-]++++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<
<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>
>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<
<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<
<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>
>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>[-]+[<++++
++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[-]+++<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<+>>>>>>>
>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[-]<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>
>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]<[-]+[>++++++++
++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>
>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<[-]>[-]+++
++++++++++++<[-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[
>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]
<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<
<[>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[
>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>[-]+++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++[>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>
>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>
>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>
>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<
<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++++[>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>
>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<+>+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]-
>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>
>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<[-]+>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-
]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>
>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-][-]<<<<<<<<<<<<<<
<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<
<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>
>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<
<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<
<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>
>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++>[-]+[<++++++++++++++++>-
]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]
<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++<<<<<<<<
<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>-]<
<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<
<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>
>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]++<[-]+[>++++++++++++++++<-][
-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]
>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<
<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>
>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<
<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+<<<<
<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>
>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]
]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>
>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>
>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<[-]+++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<
<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<[-]>>>>>>
>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<
<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>
>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<[-]]>>>[-]+++<[-]+[>++++++++++++++++<-][-]<[-]<<[>>>+<+<<-
]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<-
>[-]]<[<<<[-]+>>>[-]]<<-]>>>[-][-]+<[-]+[>++++++++++++++++<-][-]<[-]<<[>
>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>
>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>+<<
<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++++++<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++[>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<
<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>
>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++++++<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>
>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<
<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>
>>>>>>>>>>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>
>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]
<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<
<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<[-]++++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>
>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<
<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<++++
++++++++++[>++++++>+++++++>++++++++>++<<<<-]>-.>++++++.>-.++++++++.>++++
.<<+.+++++.>-.<---------.>--------.++++++.-----.+++.+++++++.>[-]<[-]<[-]
<[-]<++++++++++.[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<[>>>
>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>
>>>>>>+<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[-]<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<
<<<<<<<<-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]
<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]++++<[-]+[>+++++++++++++++
+<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<
<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-
]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<[>>>>>>>
>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>
+<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++
+++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++[>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>
>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>
>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>
>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<
<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++++++++
++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++++[>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<
<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>
>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<+>+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-
]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<
<<<<[-]]->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>
>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>
>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++>[-]+[<++++++++++++++++>-]>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+
<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<<
<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-]<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]+++++<[-]+[>++++++++++++++++<-][-]<[-
]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<
<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-
]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>
>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<
-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++[>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<
<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>
>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<[-]+++++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>
>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>
>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<<
<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>>>>>>>>>>
>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<
<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<
<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++
++++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>
>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<
<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<+++++++++++
+++++[>++++>+++++++>++++++>++>++++++>+++<<<<<<-]>+.>++.>+++++.>.<<++++++
+.----------.++++++.>>.<<--.++.---.>.>.++++++++.>-------.>-.<-----------
.<+.---------.<<<--.>>>.>>[-]<[-]<[-]<[-]<[-]<[-]>>>>>>>>>>>>>>>>>>>>>>>
>>>>,<<<[-]>>>[<<<+>>>-][-]<<<[>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>
>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>+<
<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>[-]+++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-
]+++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+++++++++++++
+++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>
>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]-
>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<
<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>
>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<[-]+++++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>
>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>
>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<<
<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>>>>>>>>>>
>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<
<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<
<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++
+++++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>
>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>[<<<<<<<
<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<++++++
+++++[>++++++++>++++++++++>+++>+++++++++<<<<-]>+.>+.++++++.>-.<--.>>.<<-
---.+++.>>++.-.<.>[-]<[-]<[-]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[>+<<<<<
<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<
<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[-]>[
-]>[-]>[-]>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<+[>+<<<<+>>>
-]<<<[>>>+<<<-]+>>>>----------[<<<<->>>>[-]]<<<<[>>+>[-]<<<-]>>[>>+<<<<+
>>-]<<[>>+<<-]+>>>>----------[<<<<->>>>[-]]<<<<[>+>[-]<<-]>>>>>>>>>>>>>>
>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<[<++++++++[>++++++>++++++<<-]
>.>.[-]<[-]]>[<<++++++++[>>++++++<<-]>>.[-]]<<++++++++[>>>++++++<<<-]>>>
.[-]<<<++++++++++++++++[>++>+++++++>+++++++<<<-]>.>.-.------.>--.++++++.
-.<<.>----.----.>-.----.-----.+++++.<++++++.<.>>+++++++++++.<++++++++.>-
---.<<.>>-.<-------.---.<.>>--.<----.>----.---.<<.>>++++.<+++++.<.>>[-]<
[-]<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>
>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>
>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<
<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+
<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<
<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<
<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>
>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++++++>[-]+[<+
+++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>+++++++++++++[>+++++++++>+++
+++++<<-]>-.-----.++++++.---.>+.<+.+.>[-]<[-]<<<<[-]+++++++++>[-]+[<++++
++++++++++++>-]>[-]]>>>[-]++++++++<[-]+[>++++++++++++++++<-][-]<[-]<<[>>
>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>
-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<[>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>
>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>
>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>[-]++++++++++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<
<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>-]>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>[>>[<+<<<+>>>>-]<<<<[>>>>+<<<<
-]+>>>[<<->>>-<<<<->>>[-]]<<<[>>[-]+<<-]>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>
>-<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>
[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<
<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<
<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++
+++++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>++++++++++++[>+
+++++++>++++++++++<<-]>+.+++.>--.<+.>--------.++++++.+.---.<.>.[-]<[-]<<
[-]]>>>[-]++++++++++<[-]+[>++++++++++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+
>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[
<<<[-]+>>>[-]]<<-]>>>[-][-]+++++++++<[-]+[>++++++++++++++++<-][-]<[-]<<[
>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>
>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>
+++++[>+++++++++<-]>+.[-]<++++++++++.[-]<[-]]>>>[-]+++++++<[-]+[>+++++++
+++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>
>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-][-]+++++++
++++<[-]+[>++++++++++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->
>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<
-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>,<<[
-]>>[<<+>>-][-]<<[>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>
>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<
<<<<<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[
-]++++++++++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>
>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<
<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<
<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<
<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<-]
[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++++++++++
+<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>
>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>
>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<
<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>>>
>>>>>>>>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>>>
>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<
<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<
<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<[-]+++++++++++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]++++++<[-]+[>++++++++++++++++
<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<
<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]
>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<[>>>>>>>>
>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+
<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++[>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<
<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>
>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>
>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++++[>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-
]]>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>
>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>
>>>>>>>>>>>>>>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>
>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>
>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<
<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<[-]++++++++++++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]
<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>
>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<[-]]>>>[-]++++++++++++<[-]+[>++++++++++++++++<-][-]<[-]<<[>>>
+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-
]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>+<<<<
<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<
<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+
<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>
>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>
>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<
<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>>>>>>>>>
>>>>>>>>>>>[-]-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>>>>>>>>>
>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<
<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<
<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+
++++++++++++>[-]+[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>
>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[
<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-][-]<<<<<<<<<<<<<<<<<<[>>>>>>>
>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>
>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-
]+++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>
>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<
<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>
>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>
>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++++++++++++++>[-]+[<++++++++++++++++>
-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-
]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++++<<<<<<
<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>-
]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<
<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>
>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]++++++++++++++<[-]+[>++++++
++++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[
>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-][-]++++++
+++++++<[-]+[>++++++++++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<
<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]
]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[
-]<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>[-]+++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<[-]+++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
++++++++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>
>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<
<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>-]<<<
<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>[-]+++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<[-]+++++++[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+++++
+++++++++++<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>-]->>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<
<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<
<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]
]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]-<<<<<<<
<<<<<<<<<<<<<<<<<<<<<[-]]->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<
<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>
>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>
>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++++++++++++++>[-]+[<+
+++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>>>
>>>[-]++<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<
+>>>>>>>>>>>>>>>>>>>>-][-]<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<
<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<
<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>
>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>
[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>
>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>
>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<
<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<[-]>[-]++[<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-
]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>
>>>>>>>>>>>>>>>>>>>>>>>>>[-]+<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>[<<<
<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>
>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<
<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-
]]>>>[-]<[-]++[>++++++++++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>
[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[
-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>[-]<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]+++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<
<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>
>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<
<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<
<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-
]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+>[-]++[
<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>[-]>>>>>>>>>>>>>>>>>>>>>>>
>>>>>[-]++<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<+>>>
>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>>>>>
>>>>[-]<<<<<<<<<<<<<<<<<<<<[-]>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<+
>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>>>[-]+<[-]++[>++
++++++++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]
<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-][-]++
+++++++++++++<[-]+[>++++++++++++++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-
]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+
>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>[-]<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<
<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]++<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<
<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>
>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<
<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<
<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]++>[-]++[
<++++++++++++++++>-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>+++++++++++[>++++++++>++++
++++++>+++>+++++++++>++++<<<<<-]>+.>+.++++++.>-.>.--.<<-------.>>>-----.
<<<++++++.>.>++++++.<<-----.>.<+++++.>>+.-------.<<.>.<+++.>>.<<++.>>>++
+++++.[-]<[-]<[-]<[-]<[-]<++++++++++.[-]<[-]]>>>[-]++<[-]++[>+++++++++++
+++++<-][-]<[-]<<[>>>+<+<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>
>-<<<<<-]>>>[<<<+>>>-]>>[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>
+<<-]>>[<<+>>-]<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<[>>
>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>
>>>+<<<<<<<<-][-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]
+<<<<<<<<<<<<<<<<<<<<<<<<[<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>
>>>>>>>>>-]->>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<-<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-
]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<-]>[>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<
<<[-]]<->>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>
>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>
>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]+++>[-]++[<++++++++++++++++>-]>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]>[-]<[-]<[>+>+<<
-]>>[<<+>>-]<[>+++++++++++[>+++++++>+++>+++++++++>++++++++++>++++<<<<<-]
>----.>-.>+.+++++.-----.>.>-----.<++++++.<<.>>+.-------.<.+.>++++.+.+.<-
---.>------.<+++.<.>>++++++.<++++.-------.>.>+++++++.[-]<[-]<[-]<[-]<[-]
<++++++++++.[-]<[-]]>>>[-]+++<[-]++[>++++++++++++++++<-][-]<[-]<<[>>>+<+
<<-]>>[<<+>>-]<[-]+>>[<<->>-]<<[>>+<[-]<<<[>>>+>>-<<<<<-]>>>[<<<+>>>-]>>
[<->[-]]<[<<<[-]+>>>[-]]<<-]>>>[-]<<[-]<[-]<[>+>+<<-]>>[<<+>>-]<[>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>+<<<
<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>-]<<<<<<<[>>>>>>>+<<<<<<<-][-]>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]<<<<<<<<<<<<<<<<<<<<<<<<[<
<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>-]->>>>>>>>>>>>>>>
>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-<+>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<-]>[>>>>>>>>
>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<<<<<<<<<<<[-]]<->>>>>>>>>>>>>>>>>>>
>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<->>>>>>>>>>>>>>>>>>>>>>>>>>>>-]<<<
<<<<<<<<<<<<<<<<<<<<<<<<<[>>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<<<<<<<<<<<<
<<<<<<<<<<<-]>>>>>>>>>>>>>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
[-]<[-]+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>[-]]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
[-]]>[-]<[-]<[>+>+<<-]>>[<<+>>-]<[<<[-]>[-]>[-]]>[-]<[-]<[>+>+<<-]>>[<<+
>>-]<[<<[-]>[-]>[-]]<<]

shinya
27-07-2008, 11:40
Se volevo offuscare qualcosa scrivevo una cosa simile a questa: :p


...lots of brainf*ck...


No quello in brainfuck non era codice offuscato, era semplicemente brainfuck.
Il codice C, quello era offuscato.

Tant'è che...


Non ho ancora capito il tuo codice , per cui non posso essere molto piu' di aiuto.

Vincenzo1968
27-07-2008, 17:20
*** Tempo per soluzione quesito C-Esperto: 0.000 secondi

*** Tempo totale per l'intera soluzione: 0.078 secondi
[/CODE]

Spero sia utile per scopi didattici e tempo permettendo sono disponibile a discuterne l'algoritmo (in special-modo per la parte C, che presenta una minima difficolta'). Un accenno sui tempo di sviluppo:


Tempo di sviluppo: 1 ora e mezza circa
Bugs scoperti dopo la prima stesura: 2
Tempo di risoluzione bugs: 10 minuti scarsi
Ottimizzazione: nessuna


Per ora non vedo bugs, ma potrebbero essercene. Nel caso qualcuno ne trovi, e' gradito un avvertimento.

Ciao repne,

mi sto studiando il tuo codice.
Utilizzi un semplice albero binario di ricerca o una delle sue forme bilanciate(Red-Black, AVL, etc) ?

rеpne scasb
27-07-2008, 17:56
Ciao repne,

mi sto studiando il tuo codice.
Utilizzi un semplice albero binario di ricerca o una delle sue forme bilanciate(Red-Black, AVL, etc) ?

Nei casi in cui una volta creato un albero binario, non sia piu' necessario aggiungere/eliminare elementi, ma solo consultarlo, puo' essere utile la sua linearizzazione. Ho quindi utilizzato un semplice albero binario e linearizzato.

Vincenzo1968
27-07-2008, 19:34
Nei casi in cui una volta creato un albero binario, non sia piu' necessario aggiungere/eliminare elementi, ma solo consultarlo, puo' essere utile la sua linearizzazione. Ho quindi utilizzato un semplice albero binario e linearizzato.

Per linearizzazione che intendi? Ho consultati due testi:

http://www.amazon.com/Introduction-Algorithms-Second-Thomas-Cormen/dp/0262531968

http://www.amazon.com/Algorithms-Parts-1-4-Fundamentals-Structures/dp/0201314525/ref=sr_1_6?ie=UTF8&s=books&qid=1217182754&sr=1-6

ma non ho trovato nulla.

rеpne scasb
27-07-2008, 21:04
Per linearizzazione che intendi? Ho consultati due testi:

http://www.amazon.com/Introduction-Algorithms-Second-Thomas-Cormen/dp/0262531968

http://www.amazon.com/Algorithms-Parts-1-4-Fundamentals-Structures/dp/0201314525/ref=sr_1_6?ie=UTF8&s=books&qid=1217182754&sr=1-6

ma non ho trovato nulla.

Una "volta" per linearizzare s'intendeva, lo srolotamento dell'albero in modo che in memoria fosse contiguamente ordinato. Per esempio, se l'albero e' composto da 100 elementi ognuno grande 10 byte, la linearizzazione comporta che per accedere all'elemento 50 ordinato (il mediano), sia necessario accedere velocemente alla locazione di memoria BASE+50*10, dove BASE e il puntatore alla testa dell'array linearizzato, 50 e' l'elemento ordinato a cui vogliamo accedere, 10 e' la dimensione in byte di ogni singolo elemento dell'albero. Nel mio software tale compito viene assolto dalla funzione Bin2Nor. Tutto questo viene fatto per fare in modo che l'accesso all'albero sia il piu' veloce possibile.

gugoXX
28-07-2008, 08:39
Aah... Stanno uscendo dei mostri!!!!

comunque


Elemento 16075394 Presente come somma di [17010]=14923802 + [6327]=1151592

cdimauro
28-07-2008, 08:48
:confused:

gugoXX
28-07-2008, 08:50
Ma no, sono peanuts, ho provato il file lungo, e a me questa risposta non risulta

Il valore 16075394 non costituisce la somma di alcuna coppia di elementi

*** Tempo per soluzione quesito C-Esperto: 2.843 secondi

A meno che abbia saltato qualcosa...

Vincenzo1968
28-07-2008, 12:27
Ma no, sono peanuts, ho provato il file lungo, e a me questa risposta non risulta

A meno che abbia saltato qualcosa...

Sono sicuro che repne saprà trovare il bug

C'era un piccolo bug anche nel mio codice.

Riporto la versione corretta che, sulla mia macchina, impiega 3172ms per riportare il risultato di "valore max non trovato".

La versione C# di Gugo, sempre sulla mia macchina, impiega 342915ms (trecentoquarantaduemilanovecentoquindici millisecondi).


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <windows.h>

#define MAX_STACK 1024
#define BUFFER_SIZE 4096

//#define NUM_INTS 100000
//#define FILENAME "C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista\\lista.txt"

#define NUM_INTS 2000000
#define FILENAME "C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista2\\lista.txt"


typedef enum tagStati
{
S_ERROR_OPEN_FILE = -2,
S_ERROR = -1,
S0 = 0,
S1
} Stati;

typedef struct tagList
{
int occorrenze;
int numero;
struct tagList *next;
} List;

typedef struct tagTree
{
int numero;
int pos;
int count;
char color;
struct tagTree *father;
struct tagTree *left;
struct tagTree *right;
} Tree;

Tree *pNil = NULL;

List *ListNewNode(int occorrenze, int numero);
void ListInsertNode(List **head, int occorrenze, int numero);
void FreeList(List** head);

void InitNil(Tree **p);
Tree *NewNode(int numero);
Tree *InsertNode(Tree *node, int numero, int pos);
void InsertFixup(Tree **head, Tree **z);
Tree *TreeRotateLeft(Tree *head, Tree *node);
Tree *TreeRotateRight(Tree *head, Tree *node);
void Search(Tree *head, Tree **result, int key);
void TreeMinimum(Tree *head, Tree **result);
void FreeTree(Tree *head);

Stati DFA(char *szFileName, int *pArray);

List *ListNewNode(int occorrenze, int numero)
{
List *r;

r = (List *) malloc(sizeof(List));

if( !r )
{
printf("Memoria insufficiente.\n");
return NULL;
}

r->occorrenze = occorrenze;
r->numero = numero;
r->next = NULL;

return r;
}

void ListInsertNode(List **head, int occorrenze, int numero)
{
List *current = *head;
List *newNode = ListNewNode(occorrenze, numero);

if ( !newNode )
return;

newNode->occorrenze = occorrenze;
newNode->numero = numero;

if ( *head == NULL ||
(*head)->occorrenze <= newNode->occorrenze )
{
newNode->next = *head;
*head = newNode;
}
else
{
while ( current->next != NULL &&
current->next->occorrenze > newNode->occorrenze )
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
}

void FreeList(List** head)
{
List *current = *head;
List *next;

while ( current != NULL )
{
next = current->next;
free(current);
current = next;
}

*head = NULL;
}

void InitNil(Tree **p)
{
*p = NewNode(0);

if ( *p )
{
(*p)->numero = 0;
(*p)->pos = 0;
(*p)->count = 0;
(*p)->color = 'b';
(*p)->left = NULL;
(*p)->right = NULL;
(*p)->father = NULL;
}
else
{
printf("Errore nell'inizializzazione di pNil.\n");
}
}

Tree *NewNode(int numero)
{
Tree *r;

r = (Tree *)malloc(sizeof(Tree));

if( !r )
{
printf("Memoria insufficiente.\n");
return pNil;
}

r->numero = numero;
r->pos = 0;
r->count = 1;
r->color = 'b'; // 'b' = Black; 'r' = Red
r->father = pNil;
r->left = pNil;
r->right = pNil;

return r;
}

Tree *InsertNode(Tree *node, int numero, int pos)
{
int nRes;
Tree *z = pNil;
Tree *y = pNil;
Tree *pRadice = pNil;

z = NewNode(numero);
if ( z == pNil )
return pNil;

pRadice = node;

while ( pRadice != pNil )
{
y = pRadice;

if ( z->numero < pRadice->numero )
nRes = -1;
else if ( z->numero > pRadice->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
pRadice = pRadice->left;
}
else if ( nRes > 0 )
{
pRadice = pRadice->right;
}
else
{
pRadice->count++;
return node;
}
}

z->pos = pos;
z->father = y;
if ( y == pNil )
{
node = z;
}
else
{
if ( z->numero < y->numero )
nRes = -1;
else if ( z->numero > y->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
y->left = z;
}
else if ( nRes > 0 )
{
y->right = z;
}
else // Trovato
{
y->count++;
return node;
}
}

z->left = pNil;
z->right = pNil;
z->color = 'r'; // Red

InsertFixup(&node, &z);

return node;
}

void InsertFixup(Tree **head, Tree **z)
{
Tree *y = pNil;

while ( (*z)->father->color == 'r' )
{
if ( (*z)->father == (*z)->father->father->left )
{
y = (*z)->father->father->right;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->right )
{
*z = (*z)->father;
*head = TreeRotateLeft(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateRight(*head, (*z)->father->father);
}
}
else
{
y = (*z)->father->father->left;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->left )
{
*z = (*z)->father;
*head = TreeRotateRight(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateLeft(*head, (*z)->father->father);
}
}
}

(*head)->color = 'b';
}

Tree *TreeRotateLeft(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->right == pNil )
return head;

y = node->right;
node->right = y->left;

if ( y->left != pNil )
{
y->left->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->left )
{
node->father->left = y;
}
else
{
node->father->right = y;
}
}

y->left = node;
node->father = y;

return head;
}

Tree *TreeRotateRight(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->left == pNil )
return head;

y = node->left;
node->left = y->right;

if ( y->right != pNil )
{
y->right->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->right )
{
node->father->right = y;
}
else
{
node->father->left = y;
}
}

y->right = node;
node->father = y;

return head;
}

void FreeTree(Tree *head)
{
Tree *temp1, *temp2;

Tree *stack[MAX_STACK];
int top;

top = 0;

if ( head == pNil )
return;

temp1 = temp2 = head;

while ( temp1 != pNil )
{
for(; temp1->left != pNil; temp1 = temp1->left)
stack[top++] = temp1;

while ( (temp1 != pNil) && (temp1->right == pNil || temp1->right == temp2) )
{
temp2 = temp1;
free(temp2);
if ( top == 0 )
return;
temp1 = stack[--top];
}

stack[top++] = temp1;
temp1 = temp1->right;
}
}

Stati DFA(char *szFileName, int *pArray)
{
Stati stato = S0;
FILE *fp;
char *buffer;
unsigned char c;
int numread = 0;
int k = 0;

int riga;
int num;
int num_righe;
int ultimo_blocco;

errno_t ferr;

riga = 0;
num_righe = 0;

ferr = fopen_s(&fp, szFileName, "rb");
if ( ferr != 0 )
{
printf("Errore nell'apertura del file %s\n", szFileName);
return S_ERROR_OPEN_FILE;
}

buffer = (char*)malloc(sizeof(char)*BUFFER_SIZE + 1);
if ( !buffer )
{
printf("Errore nell'allocazione della memoria.");
fclose(fp);
return -1;
}

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread <= 0 )
{
printf("Il file e' vuoto.\n");
return -1;
}
*(buffer + numread + 1) = '\0';
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

printf("");

k = 0;
while ( *(buffer + k++) != '\n' )
;

num = 0;
while ( 1 )
{
c = *(buffer + k++);
if ( c == EOF )
break;

if ( c == '\0' )
{
k = 0;
if ( ultimo_blocco )
break;

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

*(buffer + numread + 1) = '\0';

c = *(buffer + k++);
}

switch (stato)
{
case S0:
num = 0;
if ( c >= '0' && c <= '9' )
{
num = c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
stato = S0;
}
else
{
printf("\nErrore in S0 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;

case S1:
if ( c >= '0' && c <= '9' )
{
num = num * 10 + c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
*(pArray + riga) = num;
riga++;
//*pTree = InsertNode(*pTree, num, riga);
num = 0;
stato = S0;
}
else
{
printf("\nErrore in S1 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;
}
}

free(buffer);

if ( fp )
fclose(fp);

return stato;
}

void Search(Tree *head, Tree **result, int key)
{
Tree *node;

*result = pNil;
node = head;

if ( head == pNil )
return;

while( 1 )
{
if ( key < node->numero )
{
if ( node->left == pNil )
break;
node = node->left;
}
else if ( key > node->numero )
{
if ( node->right == pNil )
break;
node = node->right;
}
else // key == node->data
{
*result = node;
break;
}
}
}

void TreeMinimum(Tree *head, Tree **result)
{
Tree *nodo = head;

*result = pNil;

if ( nodo == pNil )
return;

*result = nodo;

while ( nodo != pNil )
{
*result = nodo;
nodo = nodo->left;
}
}

int ReverseInOrder(Tree *head, int somma)
{
int diff;

Tree *temp;
Tree *findTree = pNil;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return 0;

temp = head;

while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->right;
}
else
{
printf("Errore: lo stack e' pieno.\n");
return 0;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

diff = somma - temp->numero;
if ( diff < 0 )
return 0;

Search(head, &findTree, diff);
if ( findTree != pNil && temp != pNil )
return 1;

temp = temp->left;
}
else
{
break;
}
}
}

return 0;
}

int main()
{
int *a;

Stati stato;
Tree *p = NULL;
Tree *pmin = NULL;

DWORD ms1, ms2;

int k;
int diff;

InitNil(&pNil);

p = pNil;
pmin = pNil;

a = (int*)malloc(sizeof(int) * NUM_INTS);
if ( !a )
{
printf("Memoria insufficiente\n");
return -1;
}

stato = DFA(FILENAME, a);

ms1 = GetTickCount();

//for( k = 0; k < 100000; k++ )
for( k = 0; k < NUM_INTS; k++ )
{
p = InsertNode(p, *(a+k), k);
}

if( stato == S0 || stato == S1 )
{
//TreeMinimum(p, &pmin);
//k = pmin->numero;
k = 0;

while ( 1 )
{
diff = 19999999 - k++;

if ( !ReverseInOrder(p, diff) )
break;
}

ms2 = GetTickCount();

if ( k > 1 )
{
printf("\nIl numero piu' grande, minore di venti milioni\n");
printf("tale che non sia la somma di due valori\n");
printf("qualsiasi della lista e' -> %d\n\n", diff);
printf("k -> %d\n", k);
}
else
{
printf("\nMax < 20000000 non trovato!\n");
}

printf("\nTime -> %dms\n", ms2 - ms1);
}
else
{
printf("\nL'automa ha restituito un errore.\n");
return -1;
}

free(a);

return 0;
}


;)

gugoXX
28-07-2008, 14:57
Sono sicuro che repne saprà trovare il bug

C'era un piccolo bug anche nel mio codice.

Riporto la versione corretta che, sulla mia macchina, impiega 3172ms per riportare il risultato di "valore max non trovato".

La versione C# di Gugo, sempre sulla mia macchina, impiega 342915ms (trecentoquarantaduemilanovecentoquindici millisecondi).


sara' lento, pero' funziona.
Questo valore 78862
non e' la somma di 2 elementi della lista (ed e' il piu' alto)...

Jon_Snow
28-07-2008, 18:38
La prima linea contiene il numero di interi in questo formato
//12345//
Le linee a seguire un record per ciascun intero.
PS: Gli interi sono 100.000 (e quindi la prima riga sara' //100000//)
Si sa che sono stati cercati in modo casuale e uniforme nel range 0 - 10.010.000
(il perche' di questo 10.000 e' solo per questioni di probabilita' relativa alla domanda del 3 esercizio)



Con o senza ripetizione?

gugoXX
28-07-2008, 19:02
La prima linea contiene il numero di interi in questo formato
//12345//
Le linee a seguire un record per ciascun intero.
PS: Gli interi sono 100.000 (e quindi la prima riga sara' //100000//)
Si sa che sono stati cercati in modo casuale e uniforme nel range 0 - 10.010.000
(il perche' di questo 10.000 e' solo per questioni di probabilita' relativa alla domanda del 3 esercizio)



Con o senza ripetizione?

Con ripetizioni. Il primo punto richiede infatti, tra le altre cose, di cercare il valore piu' frequente.

morskott
28-07-2008, 20:44
Con ripetizioni. Il primo punto richiede infatti, tra le altre cose, di cercare il valore piu' frequente.

a quando il contest 4???

Jon_Snow
28-07-2008, 21:26
Valgono anche ottimizzazzioni dovute alla struttura dei dati in ingresso (in questo caso distribuiti uniformente)?

rеpne scasb
28-07-2008, 21:39
Ma no, sono peanuts, ho provato il file lungo, e a me questa risposta non risulta

A meno che abbia saltato qualcosa...

Sono sicuro che repne saprà trovare il bug

C'era un piccolo bug anche nel mio codice.

Riporto la versione corretta che, sulla mia macchina, impiega 3172ms per riportare il risultato di "valore max non trovato".

La versione C# di Gugo, sempre sulla mia macchina, impiega 342915ms (trecentoquarantaduemilanovecentoquindici millisecondi).



sara' lento, pero' funziona.
Questo valore 78862
non e' la somma di 2 elementi della lista (ed e' il piu' alto)...

Allora, la mia vecchia versione era afflitta da un bug che si manifestava con la lista da 2 milioni di elementi, in quanto tale versione dava per scontate una serie di ipotesi semplificative, non verificate nella lista da 2 milioni di elementi. Questa nuova versione e' in grado di effettuare un'analisi delle code distributive dei dati, e pare funzionare. Nello specifico il primo valore disponibile sotto 20.000.000 che non sia uguale alla somma di due elementi e': 78862 cosi' come detto da gugoXX. Il tempo impiegato sulla mia macchina e' dell'ordine di 32 millesimi di secondo, circa 1000 volte piu' veloce della versione di gugoXX.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <mem.h>

#define LEN_INPUT_LINE 32
#define N_CLK 10
#define ITEMS_SIZE 5 * sizeof(long)
#define ITEMS_ARGS (ITEMS_SIZE/sizeof(long))
#define ITEMS_RGSS (sizeof(long)<<1)
#define ITEMS_RGST ((sizeof(long)<<1)/sizeof(long))
#define N_VAL 6
#define SEARCH_LIMIT 19999999
#define INPUT_FILE_NAME "LISTA.TXT"

long * Bin2Nor(long *,long *);
int Search_Val(long,long *,long *,long *,long *,long *,long);
void Search_Non_Val(long,long *,long);

int main()

{
clock_t clk[N_CLK];
FILE *input_file;
char *input_line;
long n_element,*t_bin,*t_exa,*t_bin_tmp,*s_bin,n_rip,max_rip,i,j,k,l,pos1,pos2,sum1,sum2,input_val[N_VAL]={217660,222940,9999999,11155123,18185748,78862};

clk[0]=clock();

if((input_line=malloc(LEN_INPUT_LINE*sizeof(char)))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

if((input_file=fopen(INPUT_FILE_NAME,"r"))==NULL)
{
fprintf(stderr,"Non trovo il file " INPUT_FILE_NAME "\n");
return 1;
}

fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}

if((input_line[0]!='/')||(input_line[1]!='/')||(input_line[strlen(input_line)-2]!='/')||(input_line[strlen(input_line)-3]!='/'))
{
fprintf(stderr,"Formato irregolare");
return 1;
}

input_line[strlen(input_line)-3]=0;
n_element=atol(input_line+2);

if((t_bin=malloc(n_element*ITEMS_SIZE))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

t_bin_tmp=t_bin;
fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}
input_line[strlen(input_line)-1]=0;
*t_bin=atol(input_line);
*(t_bin+1)=*(t_bin+2)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_ARGS;

for(l=k=i=1;i<n_element;i++)
{
fgets(input_line,LEN_INPUT_LINE,input_file);
if(strlen(input_line)==LEN_INPUT_LINE-1)
{
fprintf(stderr,"Buffer di linea insufficiente\n");
return 1;
}
input_line[strlen(input_line)-1]=0;
j=atol(input_line);
t_exa=t_bin_tmp;
do
{
if(j<*t_exa)
{
if(*(t_exa+3)==NULL)
{
*(t_exa+3)=(long)t_bin;
*t_bin=j;
*(t_bin+2)=l;
*(t_bin+1)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_ARGS;
j=-1;
k++;
l++;
}
else
t_exa=(long *)*(t_exa+3);
}
else
{
if(j>*t_exa)
{
if(*(t_exa+4)==NULL)
{
*(t_exa+4)=(long)t_bin;
*t_bin=j;
*(t_bin+2)=l;
*(t_bin+1)=*(t_bin+3)=*(t_bin+4)=0;
t_bin+=ITEMS_ARGS;
j=-1;
k++;
l++;
}
else
t_exa=(long *)*(t_exa+4);
}
else
{
(*(t_exa+1))++;
l++;
j=-1;
}
}
} while (j!=-1);
}
t_bin=t_bin_tmp;

fclose(input_file);

clk[1]=clock();
printf("*** Tempo per creazione albero binario: %7.3f secondi\n",(double)(clk[1]-clk[0])/CLK_TCK);

for(max_rip=n_rip=i=0;i<k;i++,t_bin+=ITEMS_ARGS)
{
if(*(t_bin+1))
{
n_rip++;
if(*(t_bin+1)>max_rip)
max_rip=*(t_bin+1);
}
}
t_bin=t_bin_tmp;

clk[2]=clock();
printf("\nNumero di elementi con almeno 2 ripetizioni: %d\n",n_rip);
printf("Massimo numero di ripetizioni: %d\n",max_rip+1);
printf("\n*** Tempo per soluzione quesito A-Base: %7.3f secondi\n",(double)(clk[2]-clk[1])/CLK_TCK);

if((s_bin=malloc(n_element*ITEMS_RGSS))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return 1;
}

Bin2Nor(t_bin,s_bin);

free(t_bin);

clk[3]=clock();
printf("*** Tempo per alterazione albero binario: %7.3f secondi\n\n",(double)(clk[3]-clk[2])/CLK_TCK);

for(i=0;i<N_VAL;i++)
{
if(Search_Val(input_val[i],&pos1,&pos2,&sum1,&sum2,s_bin,n_element))
printf("Valore %d=%d+%d (posizioni: %d,%d)\n",input_val[i],sum1,sum2,pos1,pos2);
else
printf("Valore somma %d non trovato\n",input_val[i]);
}

clk[4]=clock();
printf("\n*** Tempo per soluzione quesito B-Avanzato: %7.3f secondi\n",(double)(clk[4]-clk[3])/CLK_TCK);

Search_Non_Val(SEARCH_LIMIT,s_bin,n_element);

clk[5]=clock();

printf("\n*** Tempo per soluzione quesito C-Esperto: %7.3f secondi\n",(double)(clk[5]-clk[4])/CLK_TCK);
printf("\n*** Tempo totale per l'intera soluzione: %7.3f secondi\n",(double)(clk[5]-clk[0])/CLK_TCK);

free(input_line);
free(s_bin);
return 0;
}

long * Bin2Nor(long *sg,long *dt)

{
long i,j;

if(sg!=NULL)
{
dt=Bin2Nor((long *)*(sg+3),dt);
for(i=0;i<(*(sg+1)+1);i++)
{
j=*sg;
*dt=j;
j=*(sg+2);
*(dt+1)=j;
dt+=ITEMS_RGST;
}
dt=Bin2Nor((long *)*(sg+4),dt);
}
return(dt);
}

int Search_Val(long input_val,long *pos1,long *pos2,long *sum1,long *sum2,long *s_bin,long k)

{
int i0,i1,im,i;

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*ITEMS_RGST);
if(i>input_val)
i1=im;
else
i0=im;
} while ((i1-i0)>1);

if(*(s_bin+i1*ITEMS_RGST)<input_val)
i0=i1;

i1=0;
do
{
i=*(s_bin+i0*ITEMS_RGST)+*(s_bin+i1*ITEMS_RGST);
if(i==input_val)
{
*sum1=*(s_bin+i1*ITEMS_RGST);
*sum2=*(s_bin+i0*ITEMS_RGST);
*pos1=*(s_bin+i1*ITEMS_RGST+1);
*pos2=*(s_bin+i0*ITEMS_RGST+1);
return 1;
}
i=i1;
i1++;
if((*(s_bin+i0*ITEMS_RGST)+*(s_bin+i1*ITEMS_RGST))>input_val)
{
i1=0;
i0--;
}
} while (i<i0);

return 0;
}

void Search_Non_Val(long input_val,long *s_bin,long k)

{
int i0,i1,im,i,min,max;
char *t_point;

i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*ITEMS_RGST);
if(i>input_val)
i1=im;
else
i0=im;
} while ((i1-i0)>1);

if(*(s_bin+i1*ITEMS_RGST)<input_val)
i0=i1;
max=i0;

min=input_val-(*(s_bin+i0*ITEMS_RGST)<<1)+(input_val>>1);

if(min>0)
{
i0=0;
i1=k-1;
do
{
im=(i1+i0)>>1;
i=*(s_bin+im*ITEMS_RGST);
if(i>min)
i1=im;
else
i0=im;
} while ((i1-i0)>1);
min=i0;
}
else
{
min=0;
max=max>>6;
}

if((t_point=calloc(input_val+1,sizeof(char)))==NULL)
{
fprintf(stderr,"Memoria insufficiente");
return;
}

i0=min;
i1=max;
do
{
i=*(s_bin+i0*ITEMS_RGST)+*(s_bin+i1*ITEMS_RGST);
if((i>input_val)||(i0==i1))
{
i0=min;
i1--;
}
else
{
i0++;
t_point[i]=1;
}
} while (i1>min);

for(i=min?input_val:*(s_bin+max*ITEMS_RGST);i;i--)
{
if(t_point[i]==0)
{
printf("\nIl valore %d non costituisce la somma di alcuna coppia di elementi\n",i);
break;
}
}

free(t_point);
}

Tipico output:

*** Tempo per creazione albero binario: 1.516 secondi

Numero di elementi con almeno 2 ripetizioni: 3674
Massimo numero di ripetizioni: 3

*** Tempo per soluzione quesito A-Base: 0.000 secondi
*** Tempo per alterazione albero binario: 0.265 secondi

Valore 217660=4289+213371 (posizioni: 633927,1468926)
Valore 222940=3081+219859 (posizioni: 437213,983730)
Valore 9999999=5596+9994403 (posizioni: 1145140,1859118)
Valore 11155123=6697+11148426 (posizioni: 55425,1547830)
Valore 18185748=8656+18177092 (posizioni: 1665,5117)
Valore somma 78862 non trovato

*** Tempo per soluzione quesito B-Avanzato: 0.000 secondi

Il valore 78862 non costituisce la somma di alcuna coppia di elementi

*** Tempo per soluzione quesito C-Esperto: 0.032 secondi

*** Tempo totale per l'intera soluzione: 1.813 secondi

gugoXX
29-07-2008, 07:33
Eccoci che voliamo piu' basso.
Cambiando l'ordine di grandezza del problema cambierei anche l'algoritmo di ricerca per il punto 3.


---------------
First Question
Numero di elementi presenti piu' di una volta: 3674
Elemento presente per piu' volte: 10121012, presente 3 volte
Time: 1845ms

---------------
Second Question
Elemento 217660 Presente come somma di [125561]=127478 + [62479]=90182
Elemento 222940 Presente come somma di [277293]=194281 + [213751]=28659
Elemento 9999999 Presente come somma di [28856]=9316096 + [22143]=683903
Elemento 11155123 Presente come somma di [95236]=9305437 + [61263]=1849686
Elemento 18185748 Presente come somma di [5117]=18177092 + [1665]=8656
Time: 94ms

---------------
Third Question
Highest not found: 78862
Time: 3558ms


L'ultimo risultato in particolare e' di 3.6 secondi, contro il 1.5 secondi della corrente versione in C.
Se non ho capito male anche per l'ultimo esercizio ti serve l'albero binario per la cui costruzione sono necessari 1.5 secondi, e ciascun punto dell'esercizio prevede la partenza dalla sola lista originale caricata in memoria.
Ti consiglio pero' di separare la lettura del file dalla trattazione, ovvero ti consiglio di creare una prima lista/array, riempirlo, e poi partire da quello per ciascun esercizio.
Penso che tu possa ottimizzare ancora il punto 2. Se ci fosse solo quello probabilmente non avresti scelto la strada dell'albero (sempre se l'hai presa, non ho capito molto il codice).

Non faccio uso di alberi, ma solo di una lista ordinata e di una Hashtable per gestire il caso particolare di quando un elemento e' la somma di due elementi identici in posizioni diverse.
Ho preso spunto da un'idea di marco.r, con una evoluzione per escludere i casi limite, e con una ottimizzazione relativa alla non considerazione di valori gia' testati in passi precedenti.

La classe per il punto 3. Poco elegante direi.

public class Question3
{
Dictionary<int, int> DictValueOcc;
int[] OrderedArrayOfKeys;
int maxToSearchFor;
bool[] map;

public Question3(IEnumerable<int> Domain, int i_maxToSearchFor)
{
maxToSearchFor = i_maxToSearchFor;
map = new bool[maxToSearchFor];

var domfiltenum = Domain.Where(t => t<maxToSearchFor);
var domfilt = domfiltenum.ToArray();

var dd = from val in domfilt
group val by val into grp
where grp.Count()>=2
select new { val = grp.Key, occ = grp.Count() };

DictValueOcc = dd.ToDictionary(t => t.val, t => t.occ);

OrderedArrayOfKeys = domfilt.Distinct().OrderBy(t => t).ToArray();

oldfirstsec = OrderedArrayOfKeys.Length - 1;
}

private int oldfirstsec = 0;
private bool IsPresentAsSum(int Search)
{
int SAnd1 = Search & 1;

if (SAnd1 == 0)
{
int Half = Search / 2;
int valuehalf;
if (DictValueOcc.TryGetValue(Half, out valuehalf))
{
if (valuehalf > 1) return true;
}
}

int len = OrderedArrayOfKeys.Length;
int prim = 0;
int sec = oldfirstsec;
int v1 = OrderedArrayOfKeys[0];
int v2 = OrderedArrayOfKeys[sec];
while (v2 > Search)
{
sec--;
v2 = OrderedArrayOfKeys[sec];
}
oldfirstsec = sec;

do
{
int tst = v1 + v2;
if (tst == Search)
{
if (prim != sec) return true;
}

if (tst >= Search)
{
sec--;
if (sec < 0) break;
v2 = OrderedArrayOfKeys[sec];
}
else
{
map[tst] = true;
prim++;
if (prim >= len) break;
v1 = OrderedArrayOfKeys[prim];
if (v1 > Search) return false;
}
}
while (true);
return false;
}

public int Result()
{
for (int sf = maxToSearchFor - 1; sf >= 0; sf--)
{
if (map[sf] == false)
{
if (!IsPresentAsSum(sf)) return sf;
}
}
return -1;
}
}

^TiGeRShArK^
29-07-2008, 09:57
come promesso a Lyane ecco la risoluzione del punto C utilizzando l'algoritmo che avevo partorito inizialmente per la risoluzione del punto B:

watch.Start();
int max = 20000000;
bool[] array = new bool[max];
list = list.Where(i => i < max).ToList();
list.ForEach(i => array[i] = true);

for (int i = max - 1; i >= 0; i--)
{
if (i % 100000 == 0)
{
list = list.Where(n => n < i).ToList();
}

if (!check(array, i))
{
Console.WriteLine("found: {0}", i);
watch.Stop();
Console.WriteLine("elapsed time: {0}ms", watch.ElapsedMilliseconds);
break;
}
}

la funzione check:

private bool check(bool[] array, int i)
{
foreach (int j in list)
{
if (i > j && array[i - j])
{
return true;
}
}
return false;
}

e l'output sotto Parallels:

found: 78862
elapsed time: 26500ms

Come primo tentativo direi che non è malaccio :p
ora vedo se mi viene in mente un algoritmo migliore in modo da competere con i vostri tempi :p

...ovviamente ho elaborato la lista grande fornita da Lyane :p

rеpne scasb
29-07-2008, 10:55
Se non ho capito male anche per l'ultimo esercizio ti serve l'albero binario per la cui costruzione sono necessari 1.5 secondi, e ciascun punto dell'esercizio...[CUT]

Per quanto riguarda il quesito C, non solo non mi serve alcun albero binario, ma non mi serve neanche i dati siano ordinati. Anzi ti diro' di piu': non mi servono neanche tutti i dati, ma solo una parte. Vi sta sfuggendo qualcosa...

Comunque il punto C, viene risolto in 32 millesimo di secondo, non in 1.5 secondi. E considera che non ho ottimizzato nulla, neanche le opzioni del compilatore C.

rеpne scasb
29-07-2008, 10:57
come promesso a Lyane ecco la risoluzione del punto C...[CUT.]

Mi pare risolto con la forza bruta (a meno di non aver frainteso). Se preparo una lista di 1 miliardo di elementi che fai? :)

^TiGeRShArK^
29-07-2008, 11:53
Mi pare risolto con la forza bruta (a meno di non aver frainteso). Se preparo una lista di 1 miliardo di elementi che fai? :)

penso ad un altro algoritmo + complesso :p
per i dati a disposizione non mi pare malaccio tenendo conto che con la seguente modifica:

int max = 20000000;
bool[] array = new bool[max];
list = (from i in list
where i < max
orderby i
select i).ToList();

list.ForEach(i => array[i] = true);

int count = list.Count;
for (int i = max - 1; i >= 0; i--)
{
if (!check(array, i, ref count))
{
watch.Stop();
Console.WriteLine("found: {0}", i);
Console.WriteLine("elapsed time: {0}ms", watch.ElapsedMilliseconds);
break;
}
}


private bool check(bool[] array, int i, ref int count)
{
for (int j = 0; j < count; j++)
{
int n = list[j];

if (i > n && array[i - n])
{
return true;
}
else if (n > i)
{
count--;
}
}
return false;
}

trova la soluzione in 11,6 secondi su una macchina virtuale :p
E credo che questo sia il limite dell'algoritmo che avevo pensato inizialmente.
Ora che il codice mi piace e che ho raggiunto il limite di ottimizzazione posso pensare a qualcos'altro. :D

Jon_Snow
29-07-2008, 12:26
Per quanto riguarda il quesito C, non solo non mi serve alcun albero binario, ma non mi serve neanche i dati siano ordinati. Anzi ti diro' di piu': non mi servono neanche tutti i dati, ma solo una parte. Vi sta sfuggendo qualcosa...

Mi sa che hai avuto un approccio molto simile al mio. Vedremo che ne esce. Che complessità ha il tuo algoritmo?

Vincenzo1968
29-07-2008, 12:36
Non riesco a trovare il bug nella mia versione :muro: .

Confermo i numeri di Repne anche sulla mia macchina:

http://img198.imageshack.us/img198/2704/puntocrepne.jpg

:)

rеpne scasb
29-07-2008, 12:40
Che complessità ha il tuo algoritmo?

Difficile da valutare, dovrei tracciare un grafico (tempo/n° dati), per avere un idea. Direi che e' "quasi" indipendente dal numero dei dati in ingresso. O meglio: si puo' rendere "quasi" indipendente.

Attendo la tua versione. Per curiosita' personale: in che linguaggio di programmazione programmi?

shinya
29-07-2008, 12:48
Per quanto riguarda il quesito C, non solo non mi serve alcun albero binario, ma non mi serve neanche i dati siano ordinati. Anzi ti diro' di piu': non mi servono neanche tutti i dati, ma solo una parte. Vi sta sfuggendo qualcosa...

Comunque il punto C, viene risolto in 32 millesimo di secondo, non in 1.5 secondi. E considera che non ho ottimizzato nulla, neanche le opzioni del compilatore C.


Ma non è che me lo spiegheresti 'sto algoritmo? Il codice è inintelligibile, per quanto mi riguarda...

rеpne scasb
29-07-2008, 12:56
Ma non è che me lo spiegheresti 'sto algoritmo? Il codice è inintelligibile, per quanto mi riguarda...

E no, adesso sono costretta ad aspettare Jon_Snow, per vedere se abbiamo pensato la stessa cosa.

Per quanto riguarda il codice inintelligibile, non c'e' soluzione in quanto mi sono resa conto da tempo, che la mia definizione di "codice leggibile" non e' propriamente quella piu' in voga.

shinya
29-07-2008, 13:07
E no, adesso sono costretta ad aspettare Jon_Snow, per vedere se abbiamo pensato la stessa cosa.

Per quanto riguarda il codice inintelligibile, non c'e' soluzione in quanto mi sono resa conto da tempo, che la mia definizione di "codice leggibile" non e' propriamente quella piu' in voga.

No ma io sono un fermo sostenitore che la leggibilità dipenda dal lettore. Però un commentino ogni tanto sullo scopo del codice... magari...

banryu79
29-07-2008, 13:19
Scusate l'intromissione. Ma ne aprofitto perchè anch'io stavo cercando di capire in dettaglio il codice postato da repne scasb.


Anzi ti diro' di piu': non mi servono neanche tutti i dati, ma solo una parte. Vi sta sfuggendo qualcosa...

Aspetto con la speranza che il contest giunga al termine per poter ascoltare la spiegazione della strategia che hai scelto e le motivazioni, naturalmente se avrai voglia di fornirle.
Mi interessa molto capire il ragionamento che hai fatto, potrebbe essermi utile per imparare qualcosa di nuovo.

rеpne scasb
29-07-2008, 13:20
No ma io sono un fermo sostenitore che la leggibilità dipenda dal lettore.

Ma certamente. Ed "IO" sono la lettrice dei miei sorgenti. Quando li modifico, li amplio, li correggo, li riutilizzo, devo poterli leggere. Quindi scrivo i miei sorgenti, in modo che dal mio punto di vista abbiano la massima leggibilita'. Ti potra' sembrare presunzione, e magari lo e', ma se scrivo un codice in modo che sia leggibile da una terza persona, poi non sara' leggibile da me a distanza, magari, di anni.

Però un commentino ogni tanto sullo scopo del codice... magari...

Un commento lo metto solo, nei punti in cui il codice non e' autoespicativo. Perche' commentare l'ovvieta'. Sarebbe come mettere un cartello appeso ad una finestra con su scritto "Finestra".

Jon_Snow
29-07-2008, 13:21
Tralasciando i dettagli (si tratta di dimostrare piccoli teoremi) la mia idea è cercare il più grande "buco" all'interno di un ben determinato range di valori possibili di una sola delle due variabili. Tale range non è tutto [0,m] dato in input, ma una porzione molto ristretta. Trovato il buco posso immediatamente, in tempo costante, sapere qual'è sarebbe stata la seconda variable che mi avrebbe generato la somma più grande e sarà proprio tale somma la soluzione cercata (il fatto che la seconda variabile sia nella lista o meno è del tutto influente).

Nella prima versione la ricerca del buco avveniva attraverso una prima fase di ordinamento senza rimozione delle ripetizioni. Sto curando come ovviare a questo limite con una ricerca randomizzata. Ed a questo che mi serve l'assunzione di uniformità dei valori.

Per ora il mio lunguaggio si chiama carta. L'implentazione poi la farò in qualsiasi cosa. Dipende da come mi gira. :)

rеpne scasb
29-07-2008, 13:22
Aspetto con la speranza che il contest giunga al termine per poter ascoltare la spiegazione della strategia che hai scelto e le motivazioni, naturalmente se avrai voglia di fornirle.
Mi interessa molto capire il ragionamento che hai fatto, potrebbe essermi utile per imparare qualcosa di nuovo.

Ok, 24-ore non si negano a nessuno. Aspettiamo Jon_Snow un giorno, e poi spiego il funzionamento della mia soluzione (che non e' la migliore possibile, quindi il contest non puo' dirsi concluso).

rеpne scasb
29-07-2008, 13:27
Tralasciando i dettagli (si tratta di dimostrare piccoli teoremi) la mia idea è cercare il più grande "buco" all'interno di un ben determinato range di valori possibili di una sola delle due variabili. Tale range non è tutto [0,m] dato in input, ma una porzione molto ristretta. Trovato il buco posso immediatamente, in tempo costante, sapere qual'è sarebbe stata la seconda variable che mi avrebbe generato la somma più grande e sarà proprio tale somma la soluzione cercata (il fatto che la seconda variabile sia nella lista o meno è del tutto influente).

Per ora il mio lunguaggio si chiama carta. L'implentazione poi la farò in qualsiasi cosa. Dipende da come mi gira. :)

Mi sembra una soluzione complessa, a "naso" definire le condizioni di funzionamento potrebbe essere di una certa complessita'. Comunque non e' la soluzione da me proposta, io ho utilizzato una serie di proprieta' del "Teorema del limite centrale".

Preparo un post con il mio algoritmo, con cui chiarisco il funzionamento.

Jon_Snow
29-07-2008, 13:51
Allora sarà tosta battere un algoritmo statistico. In genere sono i migliori. :)

rеpne scasb
29-07-2008, 14:33
Semplifico la trattazione in modo che sia comprensibile anche da chi non dispone
di conoscenze statistico/matematiche.

Siano: 'r' una lista di elementi composta da numeri interi.
'n' il numero di elementi di 'r'
'x' il piu' grande intero minore di un certo limite 'l' che non sia la
somma di due qualsiasi elementi 'r'

1) La prima considerazione da fare e' che tutti gli elementi appartenenti a 'r'
che siano piu' grandi di 'l' non sono di alcun interesse. Siano 'm' gli
elementi di 'r' con 'ni'<'l' (i=indice da 0 a 'n')

2) Consideriamo tutte le possibili somme degli 'm' elementi (m^2+m)/2.

3) Se distribuiamo tali somme avremo una distribuzione in cui sono identificabili
tre aree:

| | ********* | |
| | *** *** | |
| | ****** ****** | |
|***|*** ***|***|
-------------------------------------------
A B M C D

Tra A-B avremo somme composte da interi bassi, tra C-D somme composte da interi
grandi, tra B-C tutto il resto. Il punto A e' la somma dei due piu' piccoli
elementi 'mi', il punto D e' la somma dei due piu' grandi elementi 'mi'. Si
vuole far notare che tutte le somme sono simmetriche rispetto ad M. Questo
spiega intuitivamente perche tra A-B e C-D ci sono poche somme, mentre tra B-C
ce ne sono parecchie.

4) Ora, per come sono composte le distribuzioni somma la parte centrale B-D e' quella
dove si "addensano" tali somme. E' possibile dimostrare che le due funzioni
che descrivono la "probabilita' somma" e "probabilita' presenza non somma di
due elementi" ossia di 'x' sono una l'inverso dell'altra. Ossia piu' si
addensano le somme piu' improbabile e' che in quell'area si trovi 'x'.

5) Consideramo 'l' cioe' il nostro limite di ricerca:

se 'l' e' minore di A o maggiore di D non e' di alcun interesse, in quanto
x = l-1.

se 'l' e' compreso tra C-D allora cerchiamo tra C-D se non troviamo nulla
allora e' inutile cercare tra B-C in quanto se 'x' non lo si e' trovato tra
C-D non lo si trovera' certamente tra B-D.

se 'l' e' minore di C conviene subito cercare 'x' tra A-B.

6) B e C sono circa 3 volte la deviazione standard.

7) Tutto cio' permette di ridurre considerevolmente i tempi di ricerca.

In sostanza il modo di agire sara':

Leggo un valore di input 'a'
Se 'a'>'l' lo elimino
Se 'a'+ InfB > B o se 'a'+ SupC < C lo elimino
Utilizzo 'a' per cercare 'x' secondo quanto descritto in 5)

Due esempi chiariranno meglio il modo di agire:

1) Prendiamo la prima lista di elementi quella con 200.000 valori. Tali valori
variano tra circa 1 e 10.100.000. La somma massima e' circa 20.200.000 la
media e' circa 10.100.000. Il limite e' 20.000.000. Ci troviamo quindi tra
C-D (si puo' calcolare la deviazione standard non su tutti gli elementi ma
solo su un campione degli stessi).

2) Ora, supponiamo che in input riceviamo il valore 5.377.219, possiamo
tranquillamente scartarlo poiche 5.377.219 + (il piu' piccolo valore 'mi')
non mi porta sotto B, e 5.377.219 + (il piu' grande valore 'mi') non mi porta
sopra C. Di elementi con cui fare somme quindi, ne devo prendere veramente pochi.

3) Prendiamo la seconda lista quella di 2.000.000 di elementi. Gli elementi
variano tra circa 1 e 20.000.000 (i piu' grandi li scartiamo automaticamenti),
La somma massiamo e' circa 40.000.000 e la media e' circa 20.000.000. Ora
in questo caso il limite 'l' e' proprio la media delle somme e non ha alcun
senso cercare sotto 20.000.000, bisognera' cercare tra A-B, trascurando tutto
il resto (questo se la lista di elementi e' sufficientemente densa (NOTA 1).

NOTA 1: Per verificare che la densita' sia corretta e' necessario verificare che
x non si trovi nel limite inferiore di C, nel caso proposto in 3) detto
k=C-D e necessaro verificare che non esista x tra C e C-k (tra 40.000.000
e 39.950.000 per esempio). Nel software che ho proposto non faccio questa
verifica, quindi una lista di elementi "poco" densa generera' risultati
non veritieri.


Ci potrebbe essere qualche errore di vario genere, per la fretta di scrivere la
soluzione. Se ci sono errori fatemelo notare.

marco.r
29-07-2008, 15:54
<cut>


Ci potrebbe essere qualche errore di vario genere, per la fretta di scrivere la
soluzione. Se ci sono errori fatemelo notare.

Ottima idea. Non avevo pensato di sfruttare il fatto che la distribuzione e' nota.

banryu79
29-07-2008, 16:24
[CODE]
...omesso...

Grazie mille: alla luce di quanto hai spiegato vado a guardare il Teorema del limite centrale e poi mi rileggo il tuo codice, con pazienza e con le spiegazioni postatecredo di poterlo capire, anche se non ho una preparazione matematica adeguata.
Grazie ancora :)

rеpne scasb
29-07-2008, 17:18
Ottima idea. Non avevo pensato di sfruttare il fatto che la distribuzione e' nota.

Chi ha pensato il contest, molto probabilmente, aveva in mente una soluzione del genere; sembra fatta apposta su misura. L'idea mi e' venuta in mente quando ho letto la frase:

"Da implementarsi eventualmente come esercizio a parte, usando oppure no la funzione di cui prima, a vostra discrezione."

Da cui si capisce che utilizzare la "funzione di cui prima" non era sicuramente la soluzione ideale, e che doveva esserci una soluzione piu' efficace.:)

rеpne scasb
29-07-2008, 17:20
Grazie mille: alla luce di quanto hai spiegato vado a guardare il Teorema del limite centrale e poi mi rileggo il tuo codice, con pazienza e con le spiegazioni postatecredo di poterlo capire, anche se non ho una preparazione matematica adeguata.
Grazie ancora :)

Ottimo, se hai da chiedere chiedi. Nei limiti del mio tempo vedro' di aiutarti.:)

marco.r
29-07-2008, 18:20
Chi ha pensato il contest, molto probabilmente, aveva in mente una soluzione del genere; sembra fatta apposta su misura. L'idea mi e' venuta in mente quando ho letto la frase:

"Da implementarsi eventualmente come esercizio a parte, usando oppure no la funzione di cui prima, a vostra discrezione."

Da cui si capisce che utilizzare la "funzione di cui prima" non era sicuramente la soluzione ideale, e che doveva esserci una soluzione piu' efficace.:)

Sul fatto che non fosse l'ideale non c'erano dubbi, il problema era trovarne una migliore... :D :p

gugoXX
29-07-2008, 18:41
Chi ha pensato il contest, molto probabilmente, aveva in mente una soluzione del genere; sembra fatta apposta su misura. L'idea mi e' venuta in mente quando ho letto la frase:

"Da implementarsi eventualmente come esercizio a parte, usando oppure no la funzione di cui prima, a vostra discrezione."

Da cui si capisce che utilizzare la "funzione di cui prima" non era sicuramente la soluzione ideale, e che doveva esserci una soluzione piu' efficace.:)

Nono, non stavo pensando a nulla in particolare :D
Stavo pensando solo a non vincolare nessuno nell'utilizzo delle funzioni precedenti.
E infatti nella mia soluzione p.es. non ho utilizzato la funzione del punto2, ottimizzata per un single call, ma non per la ricerca di range.

Jon_Snow
30-07-2008, 01:06
Se la mia dimostrazione è corretta (verificherò quando implementerò) questo problema è riconducibile ad una ricerca di sottomaschere binarie.

Il mio neo è che non riesco a scendere sotto la complessità lineare nel caso medio teorico. Onestamente non so se lineare = 31ms. Vedremo se le randomizzazioni fanno il miracolo :)

DanieleC88
30-07-2008, 08:32
Mamma mia, a leggere questo thread m'è venuta seriamente paura... Non avendo niente qui giù che mi consenta di sviluppare in C avevo preparato qualche cosa in Python (per la gioia di cdimauro :D), ma ormai non mi pare più il caso. :stordita:

cdimauro
30-07-2008, 08:38
Ma-perché-no: posta pure, dai. :) Mica è una sfida a chi ce l'ha più lungo (o sì?). ;)

DanieleC88
30-07-2008, 10:45
Be', essendo un contest, in fondo credo proprio lo sia... :p

No vabbe', il fatto è che non apportavo alcun miglioramento col mio codice (un banale lentissimo ciclo che cerca i valori, su questo rottame dal quale scrivo ci mette un'eternità, ho difficoltà anche a provarlo).

Ma giacché ci siamo:
# -*- coding: cp1252 -*-
import time

def caricaLista(filename):
File = open(filename)
File.readline()

lista = []
for line in File:
lista.append(int(line))
File.close()
return lista

def risolviQuesitoA(lista):
d = {}
ripetizioni = {}

massimo = 1
for n in lista:
if not n in d:
d[n] = 1
continue
ripetizioni[n] = True
d[n] += 1
if massimo < d[n]:
massimo = d[n]
return len(ripetizioni), massimo

def Fn(lista, valore):
lunghezza = len(lista)
for x in xrange(lunghezza):
if lista[x] >= valore: continue

n = lista[x]
m = (valore - n)
if m in lista:
y = lista.index(m)
stessoElemento = (x == y)
valoriInaccettabili = (n == m and not valore == 2)
if not (stessoElemento or valoriInaccettabili):
return (x, y)
return None

def risolviQuesitoB(lista, valori):
return [Fn(lista, n) for n in valori]

def risolviQuesitoC(lista):
pass

print "Carico la lista..."
t1 = time.clock()
lista = caricaLista("lista.txt")
t2 = time.clock()
print " -> Lettura completata (%f millisecondi)." % ((t2-t1)*1000.0)
print

print "Risolvo il quesito A..."
t1 = time.clock()
ripetizioni, massimo = risolviQuesitoA(lista)
t2 = time.clock()

print " *** QUESITO A ***"
print " -> %d ripetizioni, con %d come massimo." % (ripetizioni, massimo)
print "Risolto in %f millisecondi." % ((t2-t1)*1000.0)
print

valori = [217660, 222940, 9999999, 11155123, 18185748]
print "Risolvo il quesito B..."
t1 = time.clock()
coordinate = risolviQuesitoB(lista, valori)
t2 = time.clock()

print " *** QUESITO B ***"
for v, c in zip(valori, coordinate):
print " -> %d:" % (v), c
print "Risolto in %f millisecondi." % ((t2-t1)*1000.0)
print

print "Risolvo il quesito C..."
t1 = time.clock()
risultato = risolviQuesitoC(lista)
t2 = time.clock()

print " *** QUESITO C ***"
print " ->", risultato
print "Risolto in %f millisecondi." % ((t2-t1)*1000.0)

Sul terzo punto non mi ci sono proprio messo a pensare (perciò l'ho tolto di mezzo con un banale pass :D), il secondo non so neanche se è del tutto corretto perché ci mette troppo tempo, fermandomi al primo ottengo questo output:
Carico la lista...
-> Lettura completata (5731.272733 millisecondi).

Risolvo il quesito A...
*** QUESITO A ***
-> 459 ripetizioni, con 4 come massimo.
Risolto in 1209.629729 millisecondi.
Dal tempo impiegato per la lettura potete immaginare di che computer io disponga al momento... :cry:

banryu79
30-07-2008, 11:10
@repne scasb
Non capisco questo punto:

...
2) Consideriamo tutte le possibili somme degli 'm' elementi (m^2+m)/2.
...


Perchè tutte le possibili somme includono la somma di un particolare m con se stesso?
Pensavo che un particolare m potesse essere sommato solo con gli altri m presenti e non con se stesso [quindi credo (m^2+m)/2 - m]?

Considera che di matematica non ci capisco un azz (trauma infantile con la materia :asd: )

ndakota
30-07-2008, 11:12
ho provato a farlo girare sul mio:


Carico la lista...
-> Lettura completata (128.290537 millisecondi).

Risolvo il quesito A...
*** QUESITO A ***
-> 459 ripetizioni, con 4 come massimo.
Risolto in 52.620724 millisecondi.

DanieleC88
30-07-2008, 11:56
ho provato a farlo girare sul mio:
La lettura è stata ~45 volte più veloce e la risoluzione del quesito A è stata ~23 volte più veloce... già si comincia a ragionare... :D

gugoXX
30-07-2008, 12:17
Ma-perché-no: posta pure, dai. :) Mica è una sfida a chi ce l'ha più lungo (o sì?). ;)

Ma infatti.
Il contest e' trovare l'algoritmo, non avercelo lungo...

ndakota
30-07-2008, 12:29
trovare l'algoritmo che ce l'ha più lungo :sofico:

DanieleC88
30-07-2008, 12:46
Ma infatti.
Il contest e' trovare l'algoritmo, non avercelo lungo...
Esatto, e fino a questo punto di algoritmi ne ho visto di molto migliori rispetto al mio, quindi postarlo o no non cambiava molto per quel che riguarda il contest. :)

cdimauro
30-07-2008, 13:38
Ma infatti.
Il contest e' trovare l'algoritmo, non avercelo lungo...
[IRONIC MODE ON]
Palle. La verità è la tua soluzione è più lenta di 3 ordini di grandezza. :Prrr:
[IRONIC MODE OFF]

:p
Esatto, e fino a questo punto di algoritmi ne ho visto di molto migliori rispetto al mio, quindi postarlo o no non cambiava molto per quel che riguarda il contest. :)
Allora non avrebbero dovuto postare tutti quelli che hanno proposto soluzioni soluzioni "meno buone" di quelle già postate, no? ;)
trovare l'algoritmo che ce l'ha più lungo :sofico:
Mumble. Qui servirebbe definire bene il concetto però. :D

wizard_at
30-07-2008, 15:19
mi scuso per l'inserimento non proprio lineare e pulito nella discussione MA non ho capito cosa sia questo tread, quale sia l'obbiettivo.

ci sono delle regole da seguire?

ciao grazie a tutti.

Vincenzo1968
30-07-2008, 15:20
Sono riuscito ad applicare il metodo di repne(il che, per uno completamente a digiuno di matematica, è una bella soddisfazione ;) )

http://img28.imageshack.us/img28/715/puntocvalido.jpg

Questo è il codice:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <windows.h>

#define MAX_STACK 1024
#define BUFFER_SIZE 4096

//#define NUM_INTS 100000
//#define FILENAME "C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista\\lista.txt"

#define NUM_INTS 2000000
#define FILENAME "C:\\Scaricamenti\\Temp\\Gugo\\ListaNumeri\\lista2\\lista.txt"

#define LIMITE 19999999

typedef enum tagStati
{
S_ERROR_OPEN_FILE = -2,
S_ERROR = -1,
S0 = 0,
S1
} Stati;

typedef struct tagList
{
int occorrenze;
int numero;
struct tagList *next;
} List;

typedef struct tagTree
{
int numero;
int pos;
int count;
char color;
struct tagTree *father;
struct tagTree *left;
struct tagTree *right;
} Tree;

Tree *pNil = NULL;

void InitNil(Tree **p);
Tree *NewNode(int numero);
Tree *InsertNode(Tree *node, int numero, int pos);
void InsertFixup(Tree **head, Tree **z);
Tree *TreeRotateLeft(Tree *head, Tree *node);
Tree *TreeRotateRight(Tree *head, Tree *node);
void Search(Tree *head, Tree **result, int key);
void TreeMinimum(Tree *head, Tree **result);
void FreeTree(Tree *head);

Stati DFA(char *szFileName, int *pArray);

void InitNil(Tree **p)
{
*p = NewNode(0);

if ( *p )
{
(*p)->numero = 0;
(*p)->pos = 0;
(*p)->count = 0;
(*p)->color = 'b';
(*p)->left = NULL;
(*p)->right = NULL;
(*p)->father = NULL;
}
else
{
printf("Errore nell'inizializzazione di pNil.\n");
}
}

Tree *NewNode(int numero)
{
Tree *r;

r = (Tree *)malloc(sizeof(Tree));

if( !r )
{
printf("Memoria insufficiente.\n");
return pNil;
}

r->numero = numero;
r->pos = 0;
r->count = 1;
r->color = 'b'; // 'b' = Black; 'r' = Red
r->father = pNil;
r->left = pNil;
r->right = pNil;

return r;
}

Tree *InsertNode(Tree *node, int numero, int pos)
{
int nRes;
Tree *z = pNil;
Tree *y = pNil;
Tree *pRadice = pNil;

z = NewNode(numero);
if ( z == pNil )
return pNil;

pRadice = node;

while ( pRadice != pNil )
{
y = pRadice;

if ( z->numero < pRadice->numero )
nRes = -1;
else if ( z->numero > pRadice->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
pRadice = pRadice->left;
}
else if ( nRes > 0 )
{
pRadice = pRadice->right;
}
else
{
pRadice->count++;
return node;
}
}

z->pos = pos;
z->father = y;
if ( y == pNil )
{
node = z;
}
else
{
if ( z->numero < y->numero )
nRes = -1;
else if ( z->numero > y->numero )
nRes = 1;
else
nRes = 0;

if ( nRes < 0 )
{
y->left = z;
}
else if ( nRes > 0 )
{
y->right = z;
}
else // Trovato
{
y->count++;
return node;
}
}

z->left = pNil;
z->right = pNil;
z->color = 'r'; // Red

InsertFixup(&node, &z);

return node;
}

void InsertFixup(Tree **head, Tree **z)
{
Tree *y = pNil;

while ( (*z)->father->color == 'r' )
{
if ( (*z)->father == (*z)->father->father->left )
{
y = (*z)->father->father->right;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->right )
{
*z = (*z)->father;
*head = TreeRotateLeft(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateRight(*head, (*z)->father->father);
}
}
else
{
y = (*z)->father->father->left;
if ( y->color == 'r' )
{
(*z)->father->color = 'b';
y->color = 'b';
(*z)->father->father->color = 'r';
*z = (*z)->father->father;
}
else
{
if ( *z == (*z)->father->left )
{
*z = (*z)->father;
*head = TreeRotateRight(*head, *z);
}
(*z)->father->color = 'b';
(*z)->father->father->color = 'r';
*head = TreeRotateLeft(*head, (*z)->father->father);
}
}
}

(*head)->color = 'b';
}

Tree *TreeRotateLeft(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->right == pNil )
return head;

y = node->right;
node->right = y->left;

if ( y->left != pNil )
{
y->left->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->left )
{
node->father->left = y;
}
else
{
node->father->right = y;
}
}

y->left = node;
node->father = y;

return head;
}

Tree *TreeRotateRight(Tree *head, Tree *node)
{
Tree *y;

if ( head == pNil || node == pNil )
return head;

if ( node->left == pNil )
return head;

y = node->left;
node->left = y->right;

if ( y->right != pNil )
{
y->right->father = node;
}

y->father = node->father;

if ( node->father == pNil )
{
head = y;
}
else
{
if ( node == node->father->right )
{
node->father->right = y;
}
else
{
node->father->left = y;
}
}

y->right = node;
node->father = y;

return head;
}

void FreeTree(Tree *head)
{
Tree *temp1, *temp2;

Tree *stack[MAX_STACK];
int top;

top = 0;

if ( head == pNil )
return;

temp1 = temp2 = head;

while ( temp1 != pNil )
{
for(; temp1->left != pNil; temp1 = temp1->left)
stack[top++] = temp1;

while ( (temp1 != pNil) && (temp1->right == pNil || temp1->right == temp2) )
{
temp2 = temp1;
free(temp2);
if ( top == 0 )
return;
temp1 = stack[--top];
}

stack[top++] = temp1;
temp1 = temp1->right;
}
}

Stati DFA(char *szFileName, int *pArray)
{
Stati stato = S0;
FILE *fp;
char *buffer;
unsigned char c;
int numread = 0;
int k = 0;

int riga;
int num;
int num_righe;
int ultimo_blocco;

errno_t ferr;

riga = 0;
num_righe = 0;

ferr = fopen_s(&fp, szFileName, "rb");
if ( ferr != 0 )
{
printf("Errore nell'apertura del file %s\n", szFileName);
return S_ERROR_OPEN_FILE;
}

buffer = (char*)malloc(sizeof(char)*BUFFER_SIZE + 1);
if ( !buffer )
{
printf("Errore nell'allocazione della memoria.");
fclose(fp);
return -1;
}

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread <= 0 )
{
printf("Il file e' vuoto.\n");
return -1;
}
*(buffer + numread + 1) = '\0';
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

printf("");

k = 0;
while ( *(buffer + k++) != '\n' )
;

num = 0;
while ( 1 )
{
c = *(buffer + k++);
if ( c == EOF )
break;

if ( c == '\0' )
{
k = 0;
if ( ultimo_blocco )
break;

numread = fread(buffer,
1,
BUFFER_SIZE,
fp);
if ( numread < BUFFER_SIZE )
ultimo_blocco = 1;
else
ultimo_blocco = 0;

*(buffer + numread + 1) = '\0';

c = *(buffer + k++);
}

switch (stato)
{
case S0:
num = 0;
if ( c >= '0' && c <= '9' )
{
num = c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
stato = S0;
}
else
{
printf("\nErrore in S0 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;

case S1:
if ( c >= '0' && c <= '9' )
{
num = num * 10 + c - '0';
stato = S1;
}
else if ( c == '\n' || c == '\r' )
{
*(pArray + riga) = num;
riga++;
//*pTree = InsertNode(*pTree, num, riga);
num = 0;
stato = S0;
}
else
{
printf("\nErrore in S1 <> Carattere -> %c\n", c);
fclose(fp);
return S_ERROR;
}
break;
}
}

free(buffer);

if ( fp )
fclose(fp);

return stato;
}

void Search(Tree *head, Tree **result, int key)
{
Tree *node;

*result = pNil;
node = head;

if ( head == pNil )
return;

while( 1 )
{
if ( key < node->numero )
{
if ( node->left == pNil )
break;
node = node->left;
}
else if ( key > node->numero )
{
if ( node->right == pNil )
break;
node = node->right;
}
else // key == node->data
{
*result = node;
break;
}
}
}

void TreeMinimum(Tree *head, Tree **result)
{
Tree *nodo = head;

*result = pNil;

if ( nodo == pNil )
return;

*result = nodo;

while ( nodo != pNil )
{
*result = nodo;
nodo = nodo->left;
}
}

void TreeMaximum(Tree *head, Tree **result)
{
Tree *nodo = head;

*result = pNil;

if ( nodo == pNil )
return;

*result = nodo;

while ( nodo != pNil )
{
*result = nodo;
nodo = nodo->right;
}
}

int ReverseInOrder(Tree *head, int somma)
{
int diff;

Tree *temp;
Tree *findTree = pNil;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return 0;

temp = head;

while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->right;
}
else
{
printf("Errore: lo stack e' pieno.\n");
return 0;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

diff = somma - temp->numero;
if ( diff < 0 )
return 0;

Search(head, &findTree, diff);
if ( findTree != pNil && temp != pNil )
return 1;

temp = temp->left;
}
else
{
break;
}
}
}

return 0;
}

int InOrder(Tree *head, int somma)
{
int diff;

Tree *temp;
Tree *findTree = pNil;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return 0;

temp = head;

while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->left;
}
else
{
printf("Errore: lo stack e' pieno.\n");
return 0;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

diff = somma - temp->numero;
if ( diff < 0 )
return 0;

Search(head, &findTree, diff);
if ( findTree != pNil && temp != pNil )
return 1;

temp = temp->right;
}
else
{
break;
}
}
}

return 0;
}

void MakeTreeSommeMinime(Tree *head, Tree **result)
{
int somma;

int k;

Tree *temp;
Tree *tempPrec;
Tree *findTree = pNil;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return;

temp = head;
tempPrec = pNil;

k = 0;
while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->left;
}
else
{
printf("Errore: lo stack e' pieno.\n");
return;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

k++;
if ( k > 10 )
break;

if ( tempPrec != pNil )
{
somma = temp->numero + tempPrec->numero;
*result = InsertNode(*result, somma, 0);
}

tempPrec = temp;
temp = temp->right;
}
else
{
break;
}
}
}

return;
}

void MakeTreeSommeMassime(Tree *head, Tree **result)
{
int somma;

int k;

Tree *temp;
Tree *tempPrec;
Tree *findTree = pNil;

Tree *stack[MAX_STACK];
int top;
top = -1;

if ( head == pNil )
return;

temp = head;
tempPrec = pNil;

k = 0;
while ( 1 )
{
if ( temp != pNil )
{
if ( top < MAX_STACK )
{
stack[++top] = temp; // Push
temp = temp->right;
}
else
{
printf("Errore: lo stack e' pieno.\n");
return;
}
}
else
{
if ( top >= 0 )
{
temp = stack[top--]; // Pop

if ( tempPrec != pNil )
{
somma = temp->numero + tempPrec->numero;
if ( somma < 20000000 )
{
*result = InsertNode(*result, somma, 0);
k++;
if ( k > 10 )
break;
}
}

tempPrec = temp;
temp = temp->left;
}
else
{
break;
}
}
}

return;
}

void TreeSuccessor(Tree *current, Tree **result)
{
Tree *nodo = current;

*result = pNil;

if ( nodo == pNil )
return;

if ( nodo->right != pNil )
{
nodo = nodo->right;
while ( nodo != pNil )
{
*result = nodo;
nodo = nodo->left;
}
}
else
{
*result = nodo->father;
while ( *result != pNil && nodo == (*result)->right )
{
nodo = *result;
*result = (*result)->father;
}
}
}

void TreePredecessor(Tree *current, Tree **result)
{
Tree *nodo = current;

*result = pNil;

if ( nodo == pNil )
return;

if ( nodo->left != pNil )
{
nodo = nodo->left;
while ( nodo != pNil )
{
*result = nodo;
nodo = nodo->right;
}
}
else
{
*result = nodo->father;
while ( *result != NULL && nodo == (*result)->left )
{
nodo = *result;
*result = (*result)->father;
}
}
}

int Media(int *a, int num_elem)
{
int k, n;
int res = 0;

n = 0;
for ( k = 1; k < num_elem+1; k++ )
{
if ( *(a+k) <= LIMITE )
res += (*(a+k)/k);
}

return (int)res;
}

int DeviazioneStandard(int *a, int num_elem)
{
int k;
int res;
int media;

res = 0;
media = Media(a, num_elem);

for ( k = 1; k < num_elem+1; k++ )
{
if ( *(a+k) <= LIMITE )
res += (int)( (*(a+k) - media)/k * (*(a+k) - media)/k );
}

return (int)( sqrt(res) );
}

int main()
{
int *a;

int A, B, C, D;
int dev_std;
int findCD;
int limite;
int bTrovato;

Stati stato;
Tree *p = NULL;
Tree *pmin = NULL;
Tree *pmax = NULL;
Tree *pprec = NULL;
Tree *psucc = NULL;
Tree *pSearch = NULL;

Tree *pSommeMin = NULL;
Tree *pSommeMax = NULL;

DWORD ms1, ms2;

int k;

InitNil(&pNil);

p = pNil;
pmin = pNil;
pmax = pNil;
pprec = pNil;
psucc = pNil;
pSearch = pNil;

pSommeMin = pNil;
pSommeMax = pNil;

a = (int*)malloc(sizeof(int) * NUM_INTS);
if ( !a )
{
printf("Memoria insufficiente\n");
return -1;
}

stato = DFA(FILENAME, a);

ms1 = GetTickCount();

for( k = 0; k < NUM_INTS; k++ )
{
p = InsertNode(p, *(a+k), k);
}

TreeMaximum(p, &pmax);
while ( pmax != pNil )
{
if ( pmax->numero > LIMITE )
{
TreePredecessor(pmax, &pprec);
pmax = pprec;
}
else
break;
}
TreePredecessor(pmax, &pprec);
limite = (pmax->numero + pprec->numero)/2;

MakeTreeSommeMinime(p, &pSommeMin);
MakeTreeSommeMassime(p, &pSommeMax);

TreeMinimum(pSommeMin, &pmin);
TreeMaximum(pSommeMax, &pmax);

A = pmin->numero;
D = pmax->numero;

dev_std = DeviazioneStandard(a, 100);
B = A + (dev_std * 10);
C = D - (dev_std * 10);

if ( limite < C )
findCD = 1;
else
findCD = 0;

bTrovato = 0;
if( stato == S0 || stato == S1 )
{
if ( findCD )
{
TreeMaximum(p, &pmax);
k = pmax->numero;

k = D;
while ( k >= C )
{
if ( !ReverseInOrder(p, k) )
{
bTrovato = 1;
break;
}
k--;
}
}
else
{
TreeMinimum(p, &pmin);
k = pmin->numero;

k = B;
while ( k >= A )
{
if ( !InOrder(p, k) )
{
bTrovato = 1;
break;
}
k--;
}
}

ms2 = GetTickCount();

if ( bTrovato )
printf("\n\nTrovato max -> %d\n\n", k);
else
printf("\n\nmax non esiste\n\n");

printf("\nTime -> %dms\n", ms2 - ms1);
}
else
{
printf("\nL'automa ha restituito un errore.\n");
free(a);
return -1;
}

free(a);

return 0;
}

rеpne scasb
30-07-2008, 18:28
@repne scasb
Perchè tutte le possibili somme includono la somma di un particolare m con se stesso?
Pensavo che un particolare m potesse essere sommato solo con gli altri m presenti e non con se stesso [quindi credo (m^2+m)/2 - m]?
Si esatto, mi sono solo posta nella peggiore delle ipotesi (o migliore), ossia ho considerato anche la somma con se stesso (tendo a generalizzare quando possibile). Questa quantita' e' utile per definire quanto sia "densa" la distribuzione della somma.

rеpne scasb
30-07-2008, 18:32
Sono riuscito ad applicare il metodo di repne(il che, per uno completamente a digiuno di matematica, è una bella soddisfazione ;) )

http://www.guidealgoritmi.it/images/ImgForums/puntoCvalido.jpg

Questo è il codice:...[CUT]

:)

rеpne scasb
30-07-2008, 18:38
Ma infatti.
Il contest e' trovare l'algoritmo, non avercelo lungo...

:mc::D

rеpne scasb
30-07-2008, 18:39
[IRONIC MODE ON]Mumble. Qui servirebbe definire bene il concetto però. :D

:p :p

gugoXX
30-07-2008, 19:50
:mc::D

:D
Inizia a risolvere l'esercizio, che come richiesto prevederebbe la costruzione di una funzione che accetta in ingresso la lista/array come letta da file (disordinata), per restituire il dato eventualmente trovato :ciapet:

cdimauro
31-07-2008, 07:35
mi scuso per l'inserimento non proprio lineare e pulito nella discussione MA non ho capito cosa sia questo tread, quale sia l'obbiettivo.

ci sono delle regole da seguire?

ciao grazie a tutti.
L'unica regola da seguire è quella che fa di un programmare un buon programmatore: risolvere il problema rispettandone pedissequamente le specifiche. :cool:

banryu79
31-07-2008, 08:50
Si esatto, mi sono solo posta nella peggiore delle ipotesi (o migliore), ossia ho considerato anche la somma con se stesso (tendo a generalizzare quando possibile). Questa quantita' e' utile per definire quanto sia "densa" la distribuzione della somma.
C'è una cosa che mi sfugge.
data la formula (m^2 + m)/2 nel caso di una lista iniziale di 100.000 valori avremmo: (100.000^2 + 100.000/2 = 5.000.050.000 possibili somme!

Questo valore, a cosa serve?
Sì, capisco che sia utile per definire quanto sia densa la distribuzione della somma, ma non riesco a vedere dove viene utilizzato questo valore nell'algoritmo (ammesso che venga utilizzato).

Poi ho un'altra domanda: con la formula di cui sopra abbiamo la percezione di "quanto" sia densa la distribuzione, ma la densità è circa uniforme (e se sì per qualche ragione specifica) oppure può variare anche sensibilmente?
Lo chiedo perchè leggendo questo:

Si vuole far notare che tutte le somme sono simmetriche rispetto ad M. Questo spiega intuitivamente perche tra A-B e C-D ci sono poche somme, mentre tra B-C ce ne sono parecchie.

da perfetto ignorante quello che ho capito è che proprio perchè stiamo parlando di distribuzione di somme di valori in un dato intervallo allora le cifre risultanti e la loro distribuzione tenderanno "a spalmarsi" in un certo modo, seguendo una certa legge, magari lungo una certa curva normale, e che questo è vero e tende a verificarsi maggiormente maggiore il numero degli elementi nell'intervallo.

Sono supposizioni corrette le mie?
Se sì, ciò implica anche che in caso, per esempio, di una lista di soli 1.000 valori usare questa strategia avrebbe poco senso (perchè la distribuzione sarebbe meno uniforme quindi c'è il rischio di sbagliare)

Se no, ti prego di correggermi, sempre se hai tempo e voglia :)

In ogni caso ti ringrazio repne, sei stata molto gentile.


@EDIT:
un'ultima cosa, sempre riguardo la distribuzione:

| | ********* | |
| | *** *** | |
| | ****** ****** | |
|***|*** ***|***|
-------------------------------------------
A B M C D

Il punto A e' la somma dei due piu' piccoli elementi 'mi'.
Il punto D e' la somma dei due piu' grandi elementi 'mi'.

Ok, ma il punto B e il punto C come sono determinati?

DanieleC88
31-07-2008, 11:54
Allora non avrebbero dovuto postare tutti quelli che hanno proposto soluzioni soluzioni "meno buone" di quelle già postate, no? ;)
Ma l'hanno fatto prima che arrivasse repne scasb. :D

cdimauro
31-07-2008, 12:49
Se controlli dall'inizio del thread ti accorgerai che diversi utenti hanno postato soluzioni similari. ;)

rеpne scasb
31-07-2008, 13:43
Questo valore, a cosa serve?
Sì, capisco che sia utile per definire quanto sia densa la distribuzione della somma, ma non riesco a vedere dove viene utilizzato questo valore nell'algoritmo (ammesso che venga utilizzato).

Non viene utilizzato. Si da per scontato che sia densa. Oltre che ad un'analisi delle code un fattore di analisi puo' comunque essere: se (max-min)/m > (m^2+2)/2 allora la distribuzione non e' sufficientemente densa.

Poi ho un'altra domanda: con la formula di cui sopra abbiamo la percezione di "quanto" sia densa la distribuzione, ma la densità è circa uniforme (e se sì per qualche ragione specifica) oppure può variare anche sensibilmente?
Lo chiedo perchè leggendo questo:

da perfetto ignorante quello che ho capito è che proprio perchè stiamo parlando di distribuzione di somme di valori in un dato intervallo allora le cifre risultanti e la loro distribuzione tenderanno "a spalmarsi" in un certo modo, seguendo una certa legge, magari lungo una certa curva normale, e che questo è vero e tende a verificarsi maggiormente maggiore il numero degli elementi nell'intervallo.

Viene intesa uniforme, ma chiaramente non lo e'. Si tratta di un'assunzione semplificativa, per non appesantire la trattazione.

Sono supposizioni corrette le mie?
Se sì, ciò implica anche che in caso, per esempio, di una lista di soli 1.000 valori usare questa strategia avrebbe poco senso (perchè la distribuzione sarebbe meno uniforme quindi c'è il rischio di sbagliare)

Sono corrette. Ma meno densa e' una distribuzione, piu' e' facile che tra A-B o C-D ci sia 'x'. L'unico modo in cui il software che ho sviluppato puo' non funzionare correttamente e':

"Distribuzione non densa e limite 'l' compreso tra B-C". In questo caso non funziona perche' la ricerca si restringerebbe tra A-B invece che tra A-(l-1). Considera comuqne che per gli altri casi continuerebbe a funzionare. Un miglioramento consisterebbe in una valutazione di (max-min)/m > (m^2+2)/2.

In ogni caso ti ringrazio repne, sei stata molto gentile.

Di nulla.

@EDIT:
un'ultima cosa, sempre riguardo la distribuzione:

| | ********* | |
| | *** *** | |
| | ****** ****** | |
|***|*** ***|***|
-------------------------------------------
A B M C D

Il punto A e' la somma dei due piu' piccoli elementi 'mi'.
Il punto D e' la somma dei due piu' grandi elementi 'mi'.

Ok, ma il punto B e il punto C come sono determinati?

Sono 'k' volte la devizione standard della distrubuzione somma (dipendentemente dalla "densita') (approsimabile tramite un campione, per esempio nella lista da 2.000.000 di elementi a il 5% a coda (si possono scartare tutti gli elementi piu' grandi di 100.000).

gugoXX
31-07-2008, 13:58
E' un paio di giorni che ho trovato un problema in questa soluzione.

[CODE]

Semplifico la trattazione in modo che sia comprensibile anche da chi non dispone
di conoscenze statistico/matematiche.
...

3) Se distribuiamo tali somme avremo una distribuzione in cui sono identificabili
tre aree:

| | ********* | |
| | *** *** | |
| | ****** ****** | |
|***|*** ***|***|
-------------------------------------------
A B M C D

Tra A-B avremo somme composte da interi bassi, tra C-D somme composte da interi
grandi, tra B-C tutto il resto. Il punto A e' la somma dei due piu' piccoli
elementi 'mi', il punto D e' la somma dei due piu' grandi elementi 'mi'. Si
vuole far notare che tutte le somme sono simmetriche rispetto ad M. Questo
spiega intuitivamente perche tra A-B e C-D ci sono poche somme, mentre tra B-C
ce ne sono parecchie.

4) Ora, per come sono composte le distribuzioni somma la parte centrale B-D e' quella
dove si "addensano" tali somme. E' possibile dimostrare che le due funzioni
che descrivono la "probabilita' somma" e "probabilita' presenza non somma di
due elementi" ossia di 'x' sono una l'inverso dell'altra. Ossia piu' si
addensano le somme piu' improbabile e' che in quell'area si trovi 'x'.

5) Consideramo 'l' cioe' il nostro limite di ricerca:

se 'l' e' minore di A o maggiore di D non e' di alcun interesse, in quanto
x = l-1.

se 'l' e' compreso tra C-D allora cerchiamo tra C-D se non troviamo nulla
allora e' inutile cercare tra B-C in quanto se 'x' non lo si e' trovato tra
C-D non lo si trovera' certamente tra B-D.

se 'l' e' minore di C conviene subito cercare 'x' tra A-B.

Certo. Conviene nel senso che sicuramente si trovara' qualcosa tra A-B.
Ma magari non il massimo, quello che si sta cercando.
Anche in presenza di distribuzioni uniformi.

Es: Prova ad eseguire l'algoritmo per casi tipo:
1000 elementi con valori equamente distribuiti tra 0-8000, cercando il "piu' grande valore minore o uguale a 7000, che non sia la somma di altri 2"

cionci
31-07-2008, 14:38
Infatti, anche io stavo pensando a questa cosa. Visto che si sta parlando di condizioni su una distribuzione, mi immagino che la ricerca trovi spesso una soluzione in quella porzione...ma la trova sempre ? Mi spiego, anche trovando una soluzione in quell'intervallo, come possiamo essere sicuri che quella soluzione sia la soluzione ottima se non verifichiamo anche le altre soluzioni ?

rеpne scasb
31-07-2008, 14:48
Certo. Conviene nel senso che sicuramente si trovara' qualcosa tra A-B.
Ma magari non il massimo, quello che si sta cercando.
Anche in presenza di distribuzioni uniformi.

No. Esistono teoremi appositi che permettono di dimostrare che se le condizioni sono X,Y,Z allora e' inutile cercare sopra B.

Es: Prova ad eseguire l'algoritmo per casi tipo:
1000 elementi con valori equamente distribuiti tra 0-8000, cercando il "piu' grande valore minore o uguale a 7000, che non sia la somma di altri 2"

Va fatto uno studio statistico per identificare correttamente B. Tale studio puo' essere piu' o meno rigoroso. Meno e' rigoroso piu' incerto e' il risultato. Nel caso di 1000 elementi distribuiti su 8000 valori si ha che ((1000^2+1000)/2)/16000=31 circa, che non e' un gran rapporto B=1/2M, se la media della distribuzione somma e' 8000 circa B e' circa 2500, che di fatto non e' un gran guadagno (e' probabile che uno studio rigoroso riconosca che B e' proprio 7000). In sostanza e' un algoritmo statistico ed e' rigoroso sotto ben precise condizioni al contorno.

rеpne scasb
31-07-2008, 14:51
Infatti, anche io stavo pensando a questa cosa. Visto che si sta parlando di condizioni su una distribuzione, mi immagino che la ricerca trovi spesso una soluzione in quella porzione...ma la trova sempre ? Mi spiego, anche trovando una soluzione in quell'intervallo, come possiamo essere sicuri che quella soluzione sia la soluzione ottima se non verifichiamo anche le altre soluzioni ?

Perche' esistono appositi teoremi che dimostrano tale specifica proprieta' della distribuzione somma.

rеpne scasb
31-07-2008, 15:04
Vedo che non sono stata chiara:

Il punto B, non e' costante ma varia in funzione di una serie di indicatori statistici. B puo' anche coincidere con M (la media della distribuzione somma, per distribuzione "non dense").

Non volevo tirare in ballo algoritmi piu' complessi, ma forse e' il caso.

Una trattazione rigorosa, comporterebbe la creazione di un funzione f(n), che riporta il numero di elementi non somma per numero di elementi. Ossia in base all'esempio precedente, si potrebbe creare una tabella del tipo.

elementi non somma / range di elementi
--------------------------------------
90 0-100
75 100-200
50 200-300
25 300-400
15 400-500
6 500-600
1 700-800
0 800-900

la f(n) e' una funzione di distribuzione a conca, ed in questo ipotetico caso ( i valori sono del tutto inventati), B sarebbe circa 1200. Ora per fare questo studio rigoroso si deve praticamente analissa tutta la distribuzione somma, e' per questo che si "tenta" di stimare B (o C). In questo modo B per distrubuzione "dense" e' in generale piu' grande del B calcolato in modo rigoroso, ma nonostante tutto si guadagna parecchio rispetto all'analisi dell'intera distribuzione somma.

banryu79
31-07-2008, 15:14
OT--
Cavoli, ma avete tutti solide basi matematiche qui!
(lol, forse non dovrei proprio stupirmi, in fondo è naturale che sia così visto che siete programmatori :rolleyes: ).

Mi piacerebbe partecipare a questi contest, purtroppo il mio background e il modo insolito con cui sono venuto a contatto con il mondo della programmazione non comprende, ne come bagaglio nozionistico ne come bagaglio esperienziale, una forte cultura logico-matematica, ne ho mai studiato in modo canonico e rigoroso algoritmi e strutture dati.

Però aver letto questi contest mi è stato utile per prendere consapevolezza di questo aspetto; ora includerò negli "studi del tempo libero" algoritmi e strutture dati.

@repne scasb: thanks a lot! Ora ho capito meglio, mi piacerebbe implementare questo algoritmo in Java e vedere che risultati saltano fuori.

@gugoXX & Company: magnifica l'idea dei contest, continuo a seguirvi volentierissimo!
--OT

gugoXX
31-07-2008, 15:43
Vedo che non sono stata chiara:

Il punto B, non e' costante ma varia in funzione di una serie di indicatori statistici. B puo' anche coincidere con M (la media della distribuzione somma, per distribuzione "non dense").


Bene, ma quindi come la mettiamo con l'algoritmo? Riusciamo ad aggiustarlo per farlo funzionare ed includere il calcolo del giusto B (o C)?
Immagino che per l'analisi della distribuzione e per i calcoli delle giuste sigma ci voglia del tempo... :)
(Intendo tempo computazionale, e' ovvio che ci vuole tempo umano per pensare e scrivere l'algoritmo, quindi non mi aspetto che venga fatto, a seconda degli impegni personali...).

Ancora, ricorda che la funzione per il punto C dell'esercizio ora sta accettando in input una lista gia' ordinata, e la sta usando come tale.
Anche per ordinare c'e' bisogno di tempo...
30ms crescono.

Per intanto sono sceso a 2.8 secondi, e penso di rosicchiare ancora qualcosina. Vedremo...

gugoXX
31-07-2008, 15:53
OT--
Cavoli, ma avete tutti solide basi matematiche qui!
(lol, forse non dovrei proprio stupirmi, in fondo è naturale che sia così visto che siete programmatori :rolleyes: ).

Mi piacerebbe partecipare a questi contest, purtroppo il mio background e il modo insolito con cui sono venuto a contatto con il mondo della programmazione non comprende, ne come bagaglio nozionistico ne come bagaglio esperienziale, una forte cultura logico-matematica, ne ho mai studiato in modo canonico e rigoroso algoritmi e strutture dati.

Però aver letto questi contest mi è stato utile per prendere consapevolezza di questo aspetto; ora includerò negli "studi del tempo libero" algoritmi e strutture dati.

@repne scasb: thanks a lot! Ora ho capito meglio, mi piacerebbe implementare questo algoritmo in Java e vedere che risultati saltano fuori.

@gugoXX & Company: magnifica l'idea dei contest, continuo a seguirvi volentierissimo!
--OT

Guarda, giusto per rincuorarti. Quando avevo inziato anche io avevo pochissime basi matematiche.
Non sapevo neppure che sarebbero potute servire in futuro.
E devo dire che l'informatica mi e' stata parecchio di sprono. Ho conosciuto la trigonometria prima dei miei compagni, e parti di analisi come derivate ed integrali gia' ai primi anni di superiori, proprio solo perche' venivano applicate all'informatica per risolvere qualche problema.
Tra le cose utili che non ho approfondito autonomamente invece direi il calcolo matriciale, che e' venuto con la scuola, tranne per alcune parti di calcolo delle prospettive, che mi ricordi ora. Ma giusto proprio perche' tanto i nostri processori non sono matriciali, e alla fine sempre un calcolo alla volta sanno (sapevano) fare, senno' mi sa che qualcosa sarebbe venuto natuale.

Ci sono anche ovviamente aspetti che invece ho dovuto imparare e che non non mi sono serviti un granche' in pratica. Ma comunque mi sentirei di gettare via proprio poco.

Vincenzo1968
02-08-2008, 22:47
Qualche buon testo introduttivo da consigliare?

banryu79
02-08-2008, 23:03
Qualche buon testo introduttivo da consigliare?
Mi accodo al volo alla richiesta di Vincenzo1968.
Non so se è lo stesso tipo di libro che intendenva Vincenzo1968, in tal caso mi scuso.

Io sto cercando un ottimo libro sugli algoritmi e strutture dati. Magari anche con esercizi da svolgere, non necessariamente in italiano.
Posso spendere un po' di soldini e sono appena entrato in ferie, così avrei proprio il tempo di "papparmelo" come si deve.

@gugoXX: grazie per la testimonianza rincuorante ;)

ndakota
03-08-2008, 00:33
il cormen :O "introduzione agli algoritmi e strutture dati" seconda edizione mc graw-hill autori Thomas H. Cormen e altri tre :p 1000 pagine di librone e tanti esercizi..

edit: non si basa su nessun linguaggio in particolare.. viene usato uno pseudolinguaggio definito nel libro..

Vincenzo1968
03-08-2008, 12:31
Mi accodo al volo alla richiesta di Vincenzo1968.
Non so se è lo stesso tipo di libro che intendenva Vincenzo1968, in tal caso mi scuso.

Io sto cercando un ottimo libro sugli algoritmi e strutture dati. Magari anche con esercizi da svolgere, non necessariamente in italiano.
Posso spendere un po' di soldini e sono appena entrato in ferie, così avrei proprio il tempo di "papparmelo" come si deve.

@gugoXX: grazie per la testimonianza rincuorante ;)

Ciao banryu,

no, io intendevo testi di matematica e statistica(ma figurati, non c'è bisogno di scusarsi).

Come testo introduttivo su algoritmi e strutture dati anch'io ti consiglio il libro segnalato da ndakota. Io ho comprato anche questi altri(che sono a un livello medio/avanzato):

http://www.amazon.com/Algorithms-Parts-1-4-Fundamentals-Structures/dp/0201314525/ref=sr_1_6?ie=UTF8&s=books&qid=1217182754&sr=1-6

http://www-cs-faculty.stanford.edu/~knuth/taocp.html

Quest'ultimo è una specie di enciclopedia; sono tre volumi e non vedo l'ora che escano il quarto e il quinto.

Ciao

banryu79
05-08-2008, 17:46
Scusate la risposta tardiva: essendo in ferie non godo più dell'accesso alla rete tramite LAN aziendale e a casa mia (trasferisto di fresco :D) non ho ancora l'accesso. Ora mi trovo a casa dei miei, per quello riesco a leggere e a rispondere.

Ringrazio ndakota e Vincenzo1968 per i consigli, mi sono segnato tutti i testi, per ora credo che mi prenderò il Cormen per sgranocchiarlo con comodo, poi si vedrà.
Grazie e saluti, ci vediamo in pianta stabile da fine agosto :)

Vincenzo1968
30-11-2008, 14:35
up.

Johnn
12-12-2008, 21:58
Se il contest non è scaduto :D , qualcuno mi può linkare i file di test? Quelli precedenti non riesco a scaricarli.

Grazie.