Aplicació: Alguns dibuixos
Aquesta lliçó mostra possibles solucions per a un parell d'exercicis del Jutge:
Ambdues solucions fan servir de manera natural la instrucció for
.
Exercici P29973 (Triangle)
L'enunciat és senzill: Donat un nombre n
, cal escriure un "triangle" de mida n
amb asteriscs. Per exemple, si l'entrada és 4, cal escriure
- \*\*
***
***
Com ho podem resoldre? L'observació fonamental és que el nombre d'asteriscs per línia creix d'un en un, des de 1 fins a n
. Això suggereix usar un for
amb una variable, diguem-ne i
, que contingui en tot moment el nombre d'asteriscs que cal escriure. Així, una primera aproximació a la solució és:
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
// codi per escriure i asteriscs en una línia
}
}
Ara només ens cal pensar què posar a la part que falta. Per començar, quin seria un possible codi per escriure 7
asteriscs en una línia? Aquest:
for (int j = 0; j < 7; ++j) cout << "*";
cout << endl;
Però, com que no hem d'escriure 7 asteriscs, sinó i
, el que hem de fer és senzillament reemplaçar el 7 per una i
:
for (int j = 0; j < i; ++j) cout << "*";
cout << endl;
Ajuntant-ho tot, obtenim la solució:
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < i; ++j) cout << "*";
cout << endl;
}
}
Observem que hem d'usar noms de variables diferents, i
i j
, per als dos for
, perquè un es troba dins de l'altre. Com ja sabem, no calen noms de variables diferents en bucles que es troben un a continuació de l'altre.
Finalment, i per comparació, així seria el codi si uséssim while
en lloc de for
:
int main() {
int n;
cin >> n;
int i = 1;
while (i <= n) {
int j = 0;
while (j < i) {
cout << "*";
++j;
}
cout << endl;
++i;
}
}
Exercici P72484 (Rombe)
L'enunciat és similar a l'anterior: Donat un nombre n
, cal escriure un "rombe" de mida n
amb asteriscs. Per exemple, si l'entrada és 4, cal escriure
*
***
*****
*******
*****
***
*
A dalt, encara que no es vegin, totes les línies (excepte la d'enmig) tenen espais a l'esquerra dels asteriscs. Aquí els visualitzem explícitament fent servir el símbol ␣ per remarcar els espais:
␣␣␣*
␣␣***
␣*****
*******
␣*****
␣␣***
␣␣␣*
Però el nombre d'espais depèn de la línia. Així doncs, per començar, fem una taula per veure quants espais i quants asteriscs calen en funció d'i
. De moment, conformem-nos amb les n
primeres files:
i | espais | asteriscs |
---|---|---|
1 | 3 | 1 |
2 | 2 | 3 |
3 | 1 | 5 |
4 | 0 | 7 |
Les fórmules semblen clares: calen n - i
espais i 2*i - 1
asteriscs. Així, aquesta és la part interessant del codi que escriu les n
primeres línies (ignorem el main()
i la lectura d'n
):
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < n - i; ++j) cout << " ";
for (int j = 0; j < 2*i - 1; ++j) cout << "*";
cout << endl;
}
Com que la figura és (quasi) simètrica respecte a l'eix horitzontal, una manera senzilla de dibuixar tot el rombe consisteix a copiar el for
tal qual, però fer que el segon for
s'executi des del final (i = n
) fins al principi (i >= 1
), decrementant la variable (--i
):
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < n - i; ++j) cout << " ";
for (int j = 0; j < 2*i - 1; ++j) cout << "*";
cout << endl;
}
for (int i = n; i >= 1; --i) {
for (int j = 0; j < n - i; ++j) cout << " ";
for (int j = 0; j < 2*i - 1; ++j) cout << "*";
cout << endl;
}
Provem aquest programa amb un 4. Veurem que el codi quasi funciona:
*
***
*****
*******
*******
*****
***
*
Veiem que sobra una línia del mig del rombe. Per arreglar-ho, podem simplement fer que el segon bucle comenci en n - 1
enlloc d'n
:
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < n - i; ++j) cout << " ";
for (int j = 0; j < 2*i - 1; ++j) cout << "*";
cout << endl;
}
for (int i = n - 1; i >= 1; --i) {
for (int j = 0; j < n - i; ++j) cout << " ";
for (int j = 0; j < 2*i - 1; ++j) cout << "*";
cout << endl;
}
Aquest codi ja és correcte, però es podria fer una mica millor? Per intentar-ho, mirem de trobar fórmules per al nombre d'espais i el nombre d'asteriscs que funcionin per a totes les línies:
i | espais | asteriscs |
---|---|---|
1 | 3 | 1 |
2 | 2 | 3 |
3 | 1 | 5 |
4 | 0 | 7 |
5 | 1 | 5 |
6 | 2 | 3 |
7 | 3 | 1 |
Sigui e
els nombre d'espais que calen. Podem veure la relació e
n
$ - $ i
e
és el valor absolut de la diferència entre n
i i
. I quants asteriscs calen? Sigui a
aquest nombre. A partir de la taula, observem que e
$ + $ a
$ = 2$ n
$ - 1$. Per tant, tenim que a
$ = 2$ n
$ - 2$ e
$ - 1$. Com a conclusió, aquesta és una altra solució possible (aquest cop, incloent el codi complet):
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 1; i <= 2*n - 1; ++i) {
int e = n - i;
if (e < 0) e = -e;
for (int j = 0; j < e; ++j) cout << " ";
for (int j = 0; j < 2*n - 2*e - 1; ++j) cout << "*";
cout << endl;
}
}
Lliçons.jutge.org
Jordi Petit, Salvador Roura
© Universitat Politècnica de Catalunya, 2024