/* */

1 de mayo de 2008

Problema 8.3

.
Enunciado
Una empresa con estructura "piramidal" requiere un programa que le permita procesar la liquidación de comisiones originadas por las ventas que realizaron los diferentes socios. Para esto cuenta con los siguientes archivos.

SOCIOS.dat (ordenado por fechaIngreso)

  • idSocio - 8 dígitos
  • nombre - string[30]
  • idSocioRef - 8 dígitos
  • fechaIngreso - ddmmaaaa
  • ultLiq - single (importe de la última liquidación)
  • acumLiq - double (acumulado de liquidaciones)

Este archivo contiene la información de los socios (vendedores) de la empresa. Cada socio fue referido (o reclutado) por otro socio. Esto lo refleja el campo idSocioRef. El "primer" socio (el presidente de la empresa) tendrá un idSocioRef con valor -1.

VENTAS.dat (sin orden)
  • idSocio
  • importe
Este archivo contiene el importe acumulado en el mes por las ventas de cada socio.

La política de liquidación por ventas que aplica la empresa es la siguiente: a cada socio le corresponde el 70% de sus ventas. Del 30% restante, el 70% le corresponde al socio que lo refirió y el 30% le corresponde al que refirió al que lo refirió, y así sucesivamente.

Se pide desarrollar un programa que:

1 - Imprima un listado ordenado por idSocio indicando su nombre, fecha de ingreso, liquidación anterior, última liquidación (la actual), porcentaje de incremento/decremento y total acumulado desde su ingreso.

2 - Actualice el archivo SOCIOS.dat actualizando los valores de los campos ultLiq y acumLiq.


Análisis
Antes de comenzar vamos a plantear un ejemplo de como se deben liquidar las comisiones por ventas.

El siguiente gráfico representa un ejemplo de la estructura piramidal de la empresa.



En este ejemplo vemos que Pablo, Marcos y Ana son referidos de Juan. Pedro y Martín son referidos de Pablo y José es referido de Ana. Marcos, Pedro, Martín y José no refirieron a ningún socio (no trajeron nuevos vendedores a la empresa).

Ahora supongamos que las ventas del mes fueron las siguientes:
  • Pedro: $300
  • Martín: $500
  • José: $250
  • Pablo: $600
  • Marcos: $100
  • Ana: $250
  • Juan: $200
Entonces:

De los $300 de Pedro $210 (el 70%) le corresponden a él. De los $90 restantes $63 (el 70%) le correspondes a Pablo y los $27 restantes le corresponden a Juan.

De los $500 de Martín $350 serán para él. De los $150 restantesn $105 serán para Pablo y $45 para Juan.

De los $250 de José solo te tocan a él $175. De los $75 restantes $52.5 serán para Ana y $22.5 serán para Juan.

De las ventas de Pablo, Marcos y Ana el 70% les corresponde a cada uno de ellos y el 30% le corresponden a Juan.

A Juan le corresponde el 100% de sus ventas ya que no es referido de nadie. Es "el presidente" de la empresa y, como dice el refrán: "Del pasado hasta el presente la plata es para el presidente".

Es decir: los ingresos de cada socio (ventas más comisiones) se calculan como el 70% de sus ventas más el 30% de los ingresos de sus referidos directos.

Luego de este análisis podemos plantear la estrategia y las estructuras de datos para resolver el problema de manera óptima.


La estrategia con la que resolveremos el problema será la siguiente:

1 - Indexar el archivo SOCIOS.dat en un árbol binario de búsqueda (ABB) ordenado por idSocio donde cada nodo tendrá la posición del registro en el archivo, un acumulador, el idSocioRef (idSocio del "padre" o socio que lo refirió y el puntero al los dos hijos (es un árbol binario).

2 - Recorrer el archivo VENTAS.dat y por cada registro "hacer la liquidación". Este proceso será recursivo ya que implica buscar en el ABB el nodo que corresponde al socio cuyas ventas estamos procesando, asignarle el 70% del importe y luego "hacer la liquidación" con su idSocioRef (idSocio de su padre) y el 30% restante del importe.

3 - Luego de procesar las ventas (punto 2) recorrer el ABB con un recorrido de Orden Inverso para "ver" los registros ordenados por idSocio, acceder directamente a cada registro del archivo de socios y (por cada socio) imprimir una línea del listado ya que (luego de acceder al archivo) tendremos todos los datos que necesitamos mostrar:
  • Nombre, Fecha de Ingreso y Liq. Anterior los obtenemos luego del acceso directo al archivo de socios.
  • Ultima Liquidación lo tenemos en el campo acumulador del nodo del árbol.
  • Porcentaje de Incremento/Decremento es una relación entre la última liquidación y la liquidación actual, y
  • Total Acumulado desde su Ingreso es el campo acumLiq del archivo de socios más la última liquidación.
Luego de imprimir actualizamos el archivo de socios.

Con esto podemos plantear la sección type y el programa principal.
   1:
2:type
3: // registro del archivo de socios
4: RSocio = record
5: idSocio: longint;
6: nombre: string[30];
7: idSocioRef: longint;
8: fechaIngreso: longint;
9: ultLiq: single;
10: acumLiq: double;
11: end;
12:
13: // archivo de socios
14: FSocios = file of RSocio;
15:
16: // registro del archivo de ventas
17: RVenta = record
18: idSocio: longint;
19: importe: single;
20: end;
21:
22: // archivo de ventas
23: FVentas = file of RVenta;
24:
25: // nodo y puntero del ABB
26: PArbol = ^NArbol;
27: NArbol = record
28: idSocio: longint;
29: pos: longint;
30: idSocioRef: longint;
31: acum: single;
32: izq: PArbol;
33: der: PArbol;
34: end;
35:

El programa principal refleja la estrategia planteada y lo vemos a continuación.




Como vemos, el programa principal es suficientemente claro. Abrimos los archivos y luego indexamos el archivo de socios con la función indexarSocios que devuelve un puntero a la raíz del ABB. Luego recorremos el archivo de ventas y por cada venta mandamos a "procesar la liquidación".

Luego el procedimiento listarYActualizar debe recorrer el ABB con un recorrido de orden inverso y por cada nodo acceder directamente al archivo de socios para listar y luego actualizar los importes de la última liquidación y el acumulado.

El procedimiento liquidar recibe el puntero al ABB, el idSocio que estamos liquidando y el importe de sus ventas. Basicamente lo que debe hacer es buscar al socio en el ABB, acumular el 70% de su importe e invocarse recursivamente con el 30% restante y el idSocioRef. Así hasta llegar al socio cuyo idSocioRef es -1.



El procedimiento buscarSocio busca el idSocio en el ABB. Lo analizaremos más adelante.

Siguiendo con el programa principal analizaremos el procedimiento listarYActualizar.




Como vemos, este procedimiento simplemente hace un recorrido de orden inverso sobre el ABB y por cada nodo invoca al procedimiento procesar quien imprime una línea del listado y luego actualizar el registro del archivo de socios.

Veamos ahora la función indexarSocios.



En esta función recorremos el archivo de socios y agregamos los datos de cada registro del archivo a un nodo en un ABB. Para agregar el nodo utilizamos el procedimiento que desarrollamos a continuación. Este procedimiento recibe la raíz del ABB, el registro con los datos que utilizaremos para completar la información el nodo y la posición (pos) del registro dentro del archivo.



Por último, tenemos que desarrollar la función buscarSocio que utilizamos en el procedimiento liquidar.


La función buscarSocio recibe el puntero al ABB y la clave (idSocio) por la cual buscar. Recordemos que un ABB (árbol binario de búsqueda) el criterio con el que se almacena la información es el siguiente:
  • si es menor está a la izquierda
  • si es mayor está a la derecha
Con esta premisa entonces primero preguntamos si el valor que buscamos (idSocio) es menor que el valor del nodo actual (p^.idSocio). Si es así entonces tenemos que repetir la operación considerando al hijo izquierdo del nodo p ya que (por definición) si es menor estará ubicado a la izquierda. Si no es menor entonces preguntamos si es mayor. Si es así entonces repetimos la operación pero considerando al hijo derecho de p. Si no entonces será igual y lo que retornamos es el mismo p.








Algoritmos y Estructuras de Datos UTN - UBA

.