/* */

24 de agosto de 2007

Problema 4.3

.
Enunciado
Una disquería quiere sacar estadísticas de las ventas de discos. Para ello requiere un programa que procese sus planillas de ventas mensuales, las cuales tienen la siguiente información.



Esta planilla está ordenada por código de disco y luego por día. Los días que no se registraron ventas de determinado disco no aparecen en la planilla. En el ejemplo vemos que el disco 1 solo se vendió los días 1, 2 y 6.

Se pide:

1 - Desarrollar un programa que procese la información de las planillas correspondientes a los meses 3, 5 y 8, e imprima (para cada uno de estos meses) el siguiente listado:



2 - Al finalizar el proceso (la emisión de los listados) el programa debe informar el total de productos vendidos (en general) durante los tres meses (la sumatoria de CDs+DVDs+CAS de todos los discos de todos los meses procesados).


Análisis
Comencemos por analizar un lote de datos para poder identificar con claridad la salida que debe emitir nuestro programa.

El siguiente archivo de texto representa la planilla de ventas de un mes (podría ser el mes 3 por ejemplo). Las columnas corresponden a codDisco, dia, cd, dvd, cas respectivamente. Para simplificar, las columnas de dvd y cas están en cero, por lo tanto este lote de datos representa un mes en el que solo se vendieron CDs.

loteDatos.txt
   1:
2: 1 1 3 0 0
3: 1 2 12 0 0
4: 1 3 2 0 0
5: 1 6 1 0 0
6: 1 7 8 0 0
7: 1 8 11 0 0
8: 1 9 2 0 0
9: 1 21 1 0 0
10: 2 3 10 0 0
11: 2 4 23 0 0
12: 2 5 3 0 0
13: 2 6 8 0 0
14: 2 7 12 0 0
15: 2 8 21 0 0
16: 2 9 44 0 0
17: 2 14 4 0 0
18: 2 15 6 0 0
19: 3 2 1 0 0
20: 3 14 4 0 0
21: 3 15 12 0 0
22: 3 17 35 0 0
23: 3 20 12 0 0
24: -1 -1 -1 -1 -1
25:

Vemos que el disco con código = 2 es el que se mantuvo por más días en ascenso consecutivo. Comienza el dia 5 (línea 12) y finaliza el día 9 (línea 16).

El problema en sí es un problema de corte de control por una variable: cod (código de disco).

Tenemos que emitir tres listados con el mismo formato: uno para el mes 3, uno para el mes 5 y otro para el mes 8. Los tres listados son exactamente iguales, lo que nos da la pauta de que trendremos que utilizar una función o procedimiento que reciba como parámetro el mes y luego procese la planilla de ventas correspondiente a ese mes.

Con este primer análisis podemos ver el diagrama del programa principal.



Desarrollamos una función procesarPlanilla que recibe el número de mes a procesar y retorna la cantidad de unidades vendidas durante ese mes (contando los CDs, DVDs y Cassettes de todos los discos).

En el programa principal nos limitamos a invocar a esta función pasándole cada uno de los meses que nos piden procesar, acumulamos los totales que retorna y luego mostramos la suma para resolver el punto 2 del enunciado.

El listado que nos piden en el punto 1 del enunciado lo tenemos que emitir dentro de la función, resolviendo un corte de control por 1 variable: la variable cod (código de disco).

Veamos entonces el diagrama de la función procesarPlanilla.




Como vemos, la función recibe el parámetro mes. Comienza invocando a un procedimiento titulos al que le pasa el mes como parámetro y luego resuelve el corte de control. Al final retorna el valor de una variable totPlanilla que analizeremos luego.

En este corte de control tenemos que emitir el listado que nos piden en el punto 1 del enunciado que, si lo analizamos podemos ver que se compone de tres partes: una cabecera, un cuerpo y un pie. Analicemos cada una de estar partes para ver como y donde las podemos resolver.

Cabecera del Listado:


La cabecera se emite una sola vez, y al inicio del listado. No tiene datos variables salvo (claro) el mes. Vamos desarrollar un procedimiento titulos que se ocupe de imprimir los títulos de la cabecera del listado. Este procedimiento lo invocamos en la función procesarPlanilla al inicio, antes de comenzar a resolver el corte de control.



El Cuerpo del Listado


En el cuerpo del listado debe aparecer una fila por cada disco vendido ese mes indicando el código de disco (cod), el total de unidades vendidas (en todos los formatos, todos los días del mes) y luego el porcentaje de unidades vendidas en CD, en DVD y en CAS.

Podemos deducir entonces que la información para mostrar cada fila del cuerpo del listado la tendremos disponible en finDisco ya que debemos terminar de procesar todas las ventas del disco para poder tener los totales y los porcentajes.

El Pie del Listado


Estos datos los tenemos que imprimir luego de procesar todos los discos vendidos durante el mes, es decir: en resultados.


Fundamentalmente nos están pidiendo un máximo: el disco (su código) que estuvo más días en ascenso concecutivo. Desde que día y hasta que día.

Según el lote de datos que planteamos al comienzo, el disco que estuvo más días en ascenso consecutivo fué el disco código 2, ya que desde el día 5 y terminando el día 9.

Para resolver este problema debemos considerar una secuencia. Llamaremos secuencia a un contador que incrementaremos en la siguiente circunstancia: "las ventas del día de hoy de un disco son mayores que las ventas del día de ayer del mismo disco". Si se cumple entonces se incrementa el contador. Si no se cumple entonces el contador se inicializa en 1 y se considera que la secuencia comienza nuevamente.

Volviendo a nuestro lote de datos, considerando el código de disco 1 podemos ver las siguientes secuencias:
  • desde el día 1 hasta el día 2
  • desde el día 3 hasta el día 3
  • desde el día 6 hasta el día 8
  • desde el día 9 hasta el día 9
  • desde el día 21 hasta el día 21
Vemos entonces que la mayor secuencia para el disco 1 fué de 3 días, desde el día 6 hasta el día 8. Analicemos ahora las secuencias para el disco código 2.
  • desde el día 3 al día 4
  • desde el día 5 hasta el día 9
  • desde el día 14 hasta el día 15
Entonces la mayor secuencia para el disco código 2 fué de 5 días, desde el día 5 hasta el día 9. Hasta ahora el disco código 2 es el que estuvo más días en ascenso consecutivo (comparándolo con el disco código 1). Si hacemos el mismo análisis con el disco código 3 veremos que no tiene ninguna secuencia tan larga.

Al comenzar a procesar un disco consideraremos que comienza la secuencia. Guardamos en una variable el día inicial y las ventas del día. Luego, al día siguiente preguntamos si las ventas fueron superadas entonces, subimos el máximo, si no volvemos a inicializar la secuencia asignando 1 al contador y guardando el día actual como día de inicio.



En proceso calculamos el total de unidades vendidas (cd+dvd+cas) del disco (cod) para ese día (dia) y lo asignamos en la variable u. Tenemos tres acumuladores: totC, totD y totS para acumular las ventas en CD, DVD y CAS respectivamente para luego, en finDisco calcular por porcentajes.



El manejo de la secuencia lo resolvemos en el procedimiento procesarSecuencia. Luego, el cálculo de la máxima secuencia para este disco lo resolvemos en procesarMaxAscenso.



En el procedimiento procesarSecuencia verificamos si la cantidad de unidades vendidas (u) es mayor que el máximo (hasta el momento). Si esto se verifica entonces preguntamos si el día que estamos procesando es el día siguiente al que se registró el máximo anterior. Si es así (entra en los dos ifs) entonces incrementamos el contador secCont, actualizamos el máximo secMax y guardamos el día anterior secDiaAnt. Pero en cualquier otro caso (no se superaron las ventas o el día actual no es el siguiente del día anterior) inicializamos la secuencia comenzándola en 1, considerando el máximo como u y asignando el día de hoy al día anterior.



En procesarMaxAscenso vamos manteniendo el máximo valor al que llegó secCont para luego, en finDisco poderlo comparar con los otros discos.



En finDisco tenemos que calcular los porcentajes para generar las líneas del cuerpo del listado. Luego comparamos la mayor secuencia del disco que acabamos de procesar (maxSecCont) contra el máximo general (maxDias) para resolver el pie del listado (en resultados).

Notemos que también acumulamos el total de ventas en la variable totPlanilla para luego utilizarla como valor de retorno de la función procesarPlanilla.



Por último, en inicializar inicializamos las variables totPlanilla (total de unidades vendidas en el mes) y maxDias (cantidad máxima de días que un disco estuvo en ascenso consecutivo). En resultados mostramos los resultados (pie del listado).

discos.pas
   1:
2:// imprime la cabecera del listado
3:procedure imprimirTitulos(mes: integer);
4:begin
5: writeln('Mes: ', mes);
6: write('Cod. Disco, ');
7: write('Tot. Unidades, ');
8: write('%CD, ');
9: write('%DVD, ');
10: writeln('%CAS');
11:end;
12:
13:
14:// mantiene la secuencia de ventas por disco/dia
15:procedure procesarSecuencia(
16: dia,u: longint;
17: var secMax,secDiaDesde
18: ,secDiaAnt,secCont: longint);
19:begin
20: if( u>secMax ) then begin
21: if( (secDiaAnt+1) = dia ) then begin
22: secDiaAnt:=dia;
23: secMax:=u;
24: secCont:=secCont+1;
25: end else begin
26: // reseteo la secuencia
27: secMax:=u;
28: secCont:=1;
29: secDiaAnt:=dia;
30: secDiaDesde:=dia;
31: end;
32: end else begin
33: // reseteo la secuencia
34: secMax:=u;
35: secCont:=1;
36: secDiaAnt:=dia;
37: secDiaDesde:=dia;
38: end;
39:end;
40:
41:
42:// mantiene la mayor secuencia alcanzada x disco/dia
43:procedure procesarMaxAscenso(
44: secCont,secDiaDesde:longint;
45: var maxCont,maxDiaDesde:longint);
46:begin
47: if( secCont > maxCont ) then begin
48: maxCont:=secCont;
49: maxDiaDesde:=secDiaDesde;
50: end;
51:end;
52:
53:
54:// procesa la planilla correspondiente a un mes
55:function procesarPlanilla(mes: integer): longint;
56:var
57: // variables para leer la planilla
58: cod,dia,cd,dvd,cas: longint;
59:
60: // variable de corte de control
61: codAnt: integer;
62:
63: // variables para manejar la secuencia
64: secDiaDesde, secDiaAnt: longint;
65: secCont, secMax: longint;
66:
67: // maximos de la secuencia
68: maxSecCont,maxSecDiaDesde:longint;
69:
70: // acumuladores para porcentajes
71: totC,totD,totS: longint;
72:
73: // totales y resultados
74: maxDias,maxDisco,maxDiaDesde,totPlanilla:longint;
75:
76:
77: // auxiliares
78: u, totU: longint;
79:begin
80: // imprimo los titulos
81: imprimirTitulos(mes);
82:
83: // ---------------------
84: // -- inicializar --
85: // ---------------------
86: maxDias:=0;
87: totPlanilla:=0;
88: // ---------------------
89: // -- /inicializar --
90: // ---------------------
91:
92: // leo la primer fila
93: readln(cod,dia,cd,dvd,cas);
94:
95: while( cod <> -1 ) do begin
96:
97: // --------------------
98: // -- cabDisco --
99: // --------------------
100: codAnt:=cod;
101: totC:=0;
102: totD:=0;
103: totS:=0;
104: secDiaAnt:=-10; // fuerzo la secuencia
105: secMax:=0;
106:
107: maxSecCont:=0;
108: maxSecDiaDesde:=-10;
109:
110: // --------------------
111: // -- /cabDisco --
112: // --------------------
113:
114:
115: while( cod = codAnt ) do begin
116:
117: // -----------------------
118: // -- proceso --
119: // -----------------------
120: totC:=totC+cd;
121: totD:=totD+dvd;
122: totS:=totS+cas;
123: u:=cd+dvd+cas;
124:
125: procesarSecuencia(dia,u,secMax
126: ,secDiaDesde
127: ,secDiaAnt
128: ,secCont);
129: procesarMaxAscenso(secCont
130: ,secDiaDesde
131: ,maxSecCont
132: ,maxSecDiaDesde);
133:
134: // -----------------------
135: // -- /proceso --
136: // -----------------------
137:
138:
139: // leo la siguiente fila
140: readln(cod,dia,cd,dvd,cas);
141: end;
142:
143: // --------------------
144: // -- finDisco --
145: // --------------------
146: totU:=totC+totD+totS;
147: totPlanilla:=totPlanilla+totU;
148:
149:
150: // imprimo fila del listado
151: write( totC*100/totU );
152: write( totD*100/totU );
153: writeln( totS*100/totU );
154:
155: if( maxSecCont> maxDias ) then begin
156: maxDias:=maxSecCont;
157: maxDisco:=codAnt;
158: maxDiaDesde:=maxSecDiaDesde;
159: end;
160:
161: // --------------------
162: // -- /finDisco --
163: // --------------------
164:
165: end;
166:
167: // --------------------
168: // -- resultados --
169: // --------------------
170:
171: // (MDAC='Mas Dias Ascenso Consecutivo')
172: writeln('Disco MDAC:',maxDisco);
173: writeln('Dia Desde:',maxDiaDesde);
174: writeln('Dia Hasta:',maxDiaDesde+maxDias-1);
175:
176: // ---------------------
177: // -- /resultados --
178: // ---------------------
179:
180: // retorno de la funcion
181: procesarPlanilla:=totPlanilla;
182:end;
183:
184:
185:// programa principal
186:var tot:longint;
187:begin
188: tot:=procesarPlanilla(3);
189:// tot:=tot+procesarPlanilla(5);
190:// tot:=tot+procesarPlanilla(8);
191: writeln('Total de Unidades Vendidas:',tot);
192:end.
193:
















.

No hay comentarios: