Exemplo n.º 1
0
        /// <summary>
        /// Część 1. zadania - zaplanowanie produkcji telewizorów dla pojedynczego kontrahenta.
        /// </summary>
        /// <remarks>
        /// Do przeprowadzenia testów wyznaczających maksymalną produkcję i zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
        /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
        /// </remarks>
        /// <param name="production">
        /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają limit produkcji w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
        /// </param>
        /// <param name="sales">
        /// Tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
        /// </param>
        /// <param name="storageInfo">
        /// Obiekt zawierający informacje o magazynie.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
        /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
        /// </param>
        /// <param name="weeklyPlan">
        /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
        /// </param>
        /// <returns>
        /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
        /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się maksymalna liczba wyprodukowanych telewizorów,
        /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
        /// </returns>
        public PlanData CreateSimplePlan(PlanData[] production, PlanData[] sales, PlanData storageInfo,
                                         out SimpleWeeklyPlan[] weeklyPlan)
        {
            weeklyPlan = null;
            if (!isOK(production, sales, storageInfo))
            {
                throw new ArgumentException();
            }
            int n = production.Length;

            weeklyPlan = new SimpleWeeklyPlan[n];
            for (int i = 0; i < n; ++i)
            {
                weeklyPlan[i].UnitsProduced = 0;
                weeklyPlan[i].UnitsSold     = 0;
                weeklyPlan[i].UnitsStored   = 0;
            }
            int   k = n + 2;
            int   source = 0; int sink = n + 1;
            Graph g = new AdjacencyListsGraph <SimpleAdjacencyList>(true, k);
            Graph r = new AdjacencyListsGraph <SimpleAdjacencyList>(true, k);


            for (int j = 0; j < n - 1; ++j)
            {
                g.AddEdge(new Edge(source, j + 1, production[j].Quantity)); // dodawanie produkcji      //produkcja+,   sales-,  magazynowanie-
                r.AddEdge(new Edge(source, j + 1, production[j].Value));

                g.AddEdge(new Edge(j + 1, sink, sales[j].Quantity)); // dodawanie sprzedazy
                r.AddEdge(new Edge(j + 1, sink, -sales[j].Value));

                g.AddEdge(new Edge(j + 1, j + 2, storageInfo.Quantity)); // dodawanie magazynu
                r.AddEdge(new Edge(j + 1, j + 2, storageInfo.Value));
            }

            g.AddEdge(source, n, production[n - 1].Quantity); // ostatni tydzien produkcji
            r.AddEdge(source, n, production[n - 1].Value);
            g.AddEdge(n, sink, sales[n - 1].Quantity);        // ostatni tydzien sprzedazy
            r.AddEdge(n, sink, -sales[n - 1].Value);
            (double value, double cost, Graph flow)ret = MinCostFlowGraphExtender.MinCostFlow(g, r, source, sink, false, MaxFlowGraphExtender.PushRelabelMaxFlow, null, false);
            int produced = 0;

            for (int i = 0; i < n; ++i)
            {
                produced += (int)ret.flow.GetEdgeWeight(source, i + 1);
                weeklyPlan[i].UnitsProduced = (int)ret.flow.GetEdgeWeight(source, i + 1);
                weeklyPlan[i].UnitsSold     = (int)ret.flow.GetEdgeWeight(i + 1, sink);
                if (i != n - 1)
                {
                    weeklyPlan[i].UnitsStored = (int)ret.flow.GetEdgeWeight(i + 1, i + 2);
                }
                else
                {
                    weeklyPlan[i].UnitsStored = 0;
                }
            }
            return(new PlanData {
                Quantity = produced, Value = -ret.cost
            });
        }
Exemplo n.º 2
0
 bool isOK(PlanData[] production, PlanData[,] sales, PlanData storageInfo)
 {
     if (production.Length != sales.GetLength(1))
     {
         return(false);
     }
     if (production.Length <= 0)
     {
         return(false);
     }
     if (sales.GetLength(0) <= 0)
     {
         return(false);
     }
     if (storageInfo.Value < 0 || storageInfo.Quantity < 0)
     {
         return(false);
     }
     for (int i = 0; i < production.Length; ++i)
     {
         if (production[i].Quantity < 0 || production[i].Value < 0)
         {
             return(false);
         }
         for (int j = 0; j < sales.GetLength(0); ++j)
         {
             if (sales[j, i].Value < 0 || sales[j, i].Quantity < 0)
             {
                 return(false);
             }
         }
     }
     return(true);
 }
Exemplo n.º 3
0
 bool isOK(PlanData[] production, PlanData[] sales, PlanData storageInfo)
 {
     if (production.Length != sales.Length)
     {
         return(false);
     }
     if (production.Length <= 0)
     {
         return(false);
     }
     if (sales.Length <= 0)
     {
         return(false);
     }
     if (storageInfo.Value < 0 || storageInfo.Quantity < 0)
     {
         return(false);
     }
     for (int i = 0; i < production.Length; ++i)
     {
         if (production[i].Quantity < 0 || production[i].Value < 0)
         {
             return(false);
         }
         if (sales[i].Value < 0 || sales[i].Quantity < 0)
         {
             return(false);
         }
     }
     return(true);
 }
Exemplo n.º 4
0
        /// <summary>
        /// Część 1. zadania - zaplanowanie produkcji telewizorów dla pojedynczego kontrahenta.
        /// </summary>
        /// <remarks>
        /// Do przeprowadzenia testów wyznaczających maksymalną produkcję i zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
        /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
        /// </remarks>
        /// <param name="production">
        /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają limit produkcji w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
        /// </param>
        /// <param name="sales">
        /// Tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
        /// </param>
        /// <param name="storageInfo">
        /// Obiekt zawierający informacje o magazynie.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
        /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
        /// </param>
        /// <param name="weeklyPlan">
        /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
        /// </param>
        /// <returns>
        /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
        /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się maksymalna liczba wyprodukowanych telewizorów,
        /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
        /// </returns>
        public PlanData CreateSimplePlan(PlanData[] production, PlanData[] sales, PlanData storageInfo,
                                         out SimpleWeeklyPlan[] weeklyPlan)
        {
            int weeks = production.Length;

            if (weeks == 0 || storageInfo.Quantity < 0 || storageInfo.Value < 0 || weeks != sales.Length)
            {
                throw new ArgumentException();
            }
            for (int i = 0; i < weeks; i++)
            {
                if (production[i].Quantity < 0 || production[i].Value < 0 ||
                    sales[i].Quantity < 0 || sales[i].Value < 0)
                {
                    throw new ArgumentException();
                }
            }

            Graph g = new AdjacencyListsGraph <HashTableAdjacencyList>(true, weeks + 2);
            Graph c = g.IsolatedVerticesGraph();

            //n - source
            //n+1 - target

            for (int i = 0; i < weeks; i++)
            {
                g.AddEdge(weeks, i, production[i].Quantity);
                c.AddEdge(weeks, i, production[i].Value);

                g.AddEdge(i, weeks + 1, sales[i].Quantity);
                c.AddEdge(i, weeks + 1, -sales[i].Value);

                if (i < weeks - 1)
                {
                    g.AddEdge(i, i + 1, storageInfo.Quantity);
                    c.AddEdge(i, i + 1, storageInfo.Value);
                }
            }
            (double value, double cost, Graph flow) = g.MinCostFlow(c, weeks, weeks + 1, true, MaxFlowGraphExtender.FordFulkersonDinicMaxFlow, MaxFlowGraphExtender.MKMBlockingFlow);

            weeklyPlan = new SimpleWeeklyPlan[weeks];

            for (int i = 0; i < weeks; i++)
            {
                weeklyPlan[i].UnitsProduced = (int)flow.GetEdgeWeight(weeks, i);
                weeklyPlan[i].UnitsSold     = (int)flow.GetEdgeWeight(i, weeks + 1);
                if (i < weeks - 1)
                {
                    weeklyPlan[i].UnitsStored = (int)flow.GetEdgeWeight(i, i + 1);
                }
                else
                {
                    weeklyPlan[i].UnitsStored = 0;
                }
            }

            return(new PlanData {
                Quantity = (int)value, Value = -cost
            });
        }
Exemplo n.º 5
0
 /// <summary>
 /// Część 2. zadania - zaplanowanie produkcji telewizorów dla wielu kontrahentów.
 /// </summary>
 /// <remarks>
 /// Do przeprowadzenia testów wyznaczających produkcję dającą maksymalny zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
 /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
 /// </remarks>
 /// <param name="production">
 /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
 /// Wartość pola <see cref="PlanData.Quantity"/> oznacza limit produkcji w danym tygodniu,
 /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
 /// </param>
 /// <param name="sales">
 /// Dwuwymiarowa tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
 /// Pierwszy wymiar tablicy jest równy liczbie kontrahentów, zaś drugi - liczbie tygodni w planie.
 /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
 /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
 /// Każdy wiersz tablicy odpowiada jednemu kontrachentowi.
 /// </param>
 /// <param name="storageInfo">
 /// Obiekt zawierający informacje o magazynie.
 /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
 /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
 /// </param>
 /// <param name="weeklyPlan">
 /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
 /// </param>
 /// <returns>
 /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
 /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się optymalna liczba wyprodukowanych telewizorów,
 /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
 /// </returns>
 public PlanData CreateComplexPlan(PlanData[] production, PlanData[,] sales, PlanData storageInfo,
                                   out WeeklyPlan[] weeklyPlan)
 {
     weeklyPlan = null;
     return(new PlanData {
         Quantity = -1, Value = 0
     });
 }
Exemplo n.º 6
0
        /// <summary>
        /// Część 2. zadania - zaplanowanie produkcji telewizorów dla wielu kontrahentów.
        /// </summary>
        /// <remarks>
        /// Do przeprowadzenia testów wyznaczających produkcję dającą maksymalny zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
        /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
        /// </remarks>
        /// <param name="production">
        /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza limit produkcji w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
        /// </param>
        /// <param name="sales">
        /// Dwuwymiarowa tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
        /// Pierwszy wymiar tablicy jest równy liczbie kontrahentów, zaś drugi - liczbie tygodni w planie.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
        /// Każdy wiersz tablicy odpowiada jednemu kontrachentowi.
        /// </param>
        /// <param name="storageInfo">
        /// Obiekt zawierający informacje o magazynie.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
        /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
        /// </param>
        /// <param name="weeklyPlan">
        /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
        /// </param>
        /// <returns>
        /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
        /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się optymalna liczba wyprodukowanych telewizorów,
        /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
        /// </returns>
        public PlanData CreateComplexPlan(PlanData[] production, PlanData[,] sales, PlanData storageInfo,
                                          out WeeklyPlan[] weeklyPlan)
        {
            int   verticesPerWeek = 2 + sales.GetLength(0);
            int   verticesCount   = verticesPerWeek * production.Length + 2;
            Graph initialGraph    = new AdjacencyListsGraph <HashTableAdjacencyList>(true, verticesCount);
            Graph flowsGraph      = initialGraph.IsolatedVerticesGraph();
            Graph costGraph       = initialGraph.IsolatedVerticesGraph();

            for (int week = 0; week < production.Length; week++)
            {
                flowsGraph.AddEdge(0, week * verticesPerWeek + 1, double.PositiveInfinity);
                costGraph.AddEdge(0, week * verticesPerWeek + 1, 0);

                flowsGraph.AddEdge(week * verticesPerWeek + 1, week * verticesPerWeek + 2, production[week].Quantity);
                costGraph.AddEdge(week * verticesPerWeek + 1, week * verticesPerWeek + 2, production[week].Value);


                if (production.Length - week >= 2)
                {
                    flowsGraph.AddEdge(week * verticesPerWeek + 2, week * verticesPerWeek + verticesPerWeek + 2, storageInfo.Quantity);
                    costGraph.AddEdge(week * verticesPerWeek + 2, (week + 1) * verticesPerWeek + 2, storageInfo.Value);
                }
                //for (int i = 0; i < length; i++)
                //{

                //}
                //flowsGraph.AddEdge(week * verticesPerWeek + 2, week * verticesPerWeek + 3, sales[week].Quantity);
                //costGraph.AddEdge(week * verticesPerWeek + 2, week * verticesPerWeek + 3, -sales[week].Value);

                flowsGraph.AddEdge(week * verticesPerWeek + 3, verticesCount - 1, double.PositiveInfinity);
                costGraph.AddEdge(week * verticesPerWeek + 3, verticesCount - 1, 0);
            }


            (double tvQuantity, double cost, Graph resultFlow) = flowsGraph.MinCostFlow(costGraph, 0, verticesCount - 1, true);


            weeklyPlan = new WeeklyPlan[production.Length];
            for (int week = 0; week < production.Length; week++)
            {
                weeklyPlan[week].UnitsProduced = (int)resultFlow.GetEdgeWeight(week * verticesPerWeek + 1, week * verticesPerWeek + 2);
                //weeklyPlan[week].UnitsSold = (int)resultFlow.GetEdgeWeight(week * verticesPerWeek + 2, week * verticesPerWeek + 3);
                if (production.Length - week >= 2)
                {
                    weeklyPlan[week].UnitsStored = (int)resultFlow.GetEdgeWeight(week * verticesPerWeek + 2, (week + 1) * verticesPerWeek + 2);
                }
                else
                {
                    weeklyPlan[week].UnitsStored = 0;
                }
            }
            return(new PlanData {
                Quantity = (int)tvQuantity, Value = -cost
            });
        }
Exemplo n.º 7
0
        /// <summary>
        /// Część 1. zadania - zaplanowanie produkcji telewizorów dla pojedynczego kontrahenta.
        /// </summary>
        /// <remarks>
        /// Do przeprowadzenia testów wyznaczających maksymalną produkcję i zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
        /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
        /// </remarks>
        /// <param name="production">
        /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają limit produkcji w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
        /// </param>
        /// <param name="sales">
        /// Tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
        /// </param>
        /// <param name="storageInfo">
        /// Obiekt zawierający informacje o magazynie.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
        /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
        /// </param>
        /// <param name="weeklyPlan">
        /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
        /// </param>
        /// <returns>
        /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
        /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się maksymalna liczba wyprodukowanych telewizorów,
        /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
        /// </returns>
        public PlanData CreateSimplePlan(PlanData[] production, PlanData[] sales, PlanData storageInfo,
                                         out SimpleWeeklyPlan[] weeklyPlan)
        {
            //Check sanity
            if (storageInfo.Value < 0 || storageInfo.Quantity < 0 || production.Length == 0 || production.Length != sales.Length)
            {
                throw new ArgumentException();
            }

            //Create graphs for Capacities and Costs
            Graph Capacities = new AdjacencyListsGraph <SimpleAdjacencyList>(true, production.Length + 2);
            Graph Costs      = new AdjacencyListsGraph <SimpleAdjacencyList>(true, production.Length + 2);

            //Hard-wire IDs special vertices
            int source = production.Length;
            int target = production.Length + 1;

            //Populate graphs with edges
            for (int i = 0; i < production.Length; i++)
            {
                //Check sanity
                if (production[i].Value < 0 || production[i].Quantity < 0 || sales[i].Quantity < 0 || sales[i].Value < 0)
                {
                    throw new ArgumentException();
                }

                //For Capacities
                Capacities.AddEdge(source, i, production[i].Quantity);
                Capacities.AddEdge(i, target, sales[i].Quantity);

                //For Costs
                Costs.AddEdge(source, i, production[i].Value);
                Costs.AddEdge(i, target, -sales[i].Value);

                //Edge for magazine purposes
                if (i < production.Length - 1)
                {
                    Capacities.AddEdge(i, i + 1, storageInfo.Quantity);
                    Costs.AddEdge(i, i + 1, storageInfo.Value);
                }
            }

            //Generate the flow
            (double value, double cost, Graph flow) = MinCostFlowGraphExtender.MinCostFlow(Capacities, Costs, source, target, false, MaxFlowGraphExtender.PushRelabelMaxFlow);

            //Construct weekly plan
            weeklyPlan = new SimpleWeeklyPlan[production.Length];
            for (int i = 0; i < production.Length; i++)
            {
                int unitsStored   = (int)flow.GetEdgeWeight(i, i + 1);
                int unitsSold     = (int)flow.GetEdgeWeight(i, target);
                int unitsProduced = (int)flow.GetEdgeWeight(source, i);

                weeklyPlan[i].UnitsStored   = unitsStored > 0 ?(int)flow.GetEdgeWeight(i, i + 1) : 0;
                weeklyPlan[i].UnitsSold     = unitsSold > 0 ? (int)flow.GetEdgeWeight(i, target) : 0;
                weeklyPlan[i].UnitsProduced = unitsProduced > 0 ? (int)flow.GetEdgeWeight(source, i) : 0;
            }

            return(new PlanData {
                Quantity = (int)value, Value = -cost
            });
        }
Exemplo n.º 8
0
        /// <summary>
        /// Część 2. zadania - zaplanowanie produkcji telewizorów dla wielu kontrahentów.
        /// </summary>
        /// <remarks>
        /// Do przeprowadzenia testów wyznaczających produkcję dającą maksymalny zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
        /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
        /// </remarks>
        /// <param name="production">
        /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza limit produkcji w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
        /// </param>
        /// <param name="sales">
        /// Dwuwymiarowa tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
        /// Pierwszy wymiar tablicy jest równy liczbie kontrahentów, zaś drugi - liczbie tygodni w planie.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
        /// Każdy wiersz tablicy odpowiada jednemu kontrachentowi.
        /// </param>
        /// <param name="storageInfo">
        /// Obiekt zawierający informacje o magazynie.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
        /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
        /// </param>
        /// <param name="weeklyPlan">
        /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
        /// </param>
        /// <returns>
        /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
        /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się optymalna liczba wyprodukowanych telewizorów,
        /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
        /// </returns>
        public PlanData CreateComplexPlan(PlanData[] production, PlanData[,] sales, PlanData storageInfo,
                                          out WeeklyPlan[] weeklyPlan)
        {
            int c = sales.GetLength(0); //Contrahents no
            int n = sales.GetLength(1); //Weeks no

            //Check sanity
            if (storageInfo.Value < 0 || storageInfo.Quantity < 0 || c == 0 || n == 0 || n != production.Length)
            {
                throw new ArgumentException();
            }

            //Create graphs for Capacities and Costs
            Graph Capacities = new AdjacencyListsGraph <SimpleAdjacencyList>(true, 2 * n + c + 2);
            Graph Costs      = new AdjacencyListsGraph <SimpleAdjacencyList>(true, 2 * n + c + 2);

            //Vertices explanation:
            //n for n weeks
            //n for n magazines (one state for each week)
            //c for c contrahents
            //plus 2 extra vertices for source and target

            //Vertices definitions:

            //Source and targer
            int source = 2 * n + c + 1;
            int target = 2 * n + c;

            //Week main vertices
            int weeksStart = 0;

            //Week magazine vertices
            int weekMagStart = n;

            //Contrahents vertices
            int contrStart = 2 * n;

            //Populate edges going out of / going into week vertices
            for (int i = 0; i < n; i++)
            {
                //Check sanity
                if (production[i].Value < 0 || production[i].Quantity < 0)
                {
                    throw new ArgumentException();
                }

                int w = weeksStart + i; //current magazine week vertex
                int v = weekMagStart + i;

                //from source to v
                Capacities.AddEdge(source, w, production[i].Quantity);
                Costs.AddEdge(source, w, production[i].Value);

                //from v to target
                Capacities.AddEdge(w, target, production[i].Quantity);
                Costs.AddEdge(w, target, -production[i].Value);

                //from v to corresponding magazine
                Capacities.AddEdge(w, v, production[i].Quantity);
                Costs.AddEdge(w, v, 0);

                //Populate edges between magazine vertices
                if (i <= n - 2)
                {
                    int nextV = weekMagStart + i + 1;
                    Capacities.AddEdge(v, nextV, storageInfo.Quantity);
                    Costs.AddEdge(v, nextV, storageInfo.Value);
                }

                //Populate edges going out of week magazine vertices into contrahents' vertices
                for (int j = 0; j < c; j++)
                {
                    if (sales[j, i].Quantity < 0 || sales[j, i].Value < 0)
                    {
                        throw new ArgumentException();
                    }

                    int    con   = contrStart + j; //Contrahent vertex
                    int    quant = sales[j, i].Quantity;
                    double val   = sales[j, i].Value;

                    Capacities.AddEdge(v, con, quant);
                    Costs.AddEdge(v, con, -val);
                }
            }

            //Populate edges going from contrahents to sink (probably could be embedded into one of the 'main' previous loops, just testing for now
            for (int i = 0; i < c; i++)
            {
                int v = contrStart + i;
                Capacities.AddEdge(v, target, int.MaxValue);
                Costs.AddEdge(v, target, 0);
            }

            //Generate the flow
            (double value, double cost, Graph flow) = MinCostFlowGraphExtender.MinCostFlow(Capacities, Costs, source, target, true, MaxFlowGraphExtender.PushRelabelMaxFlow);

            //Calculate quantity produced
            weeklyPlan = new WeeklyPlan[n];
            int    quantity = 0;
            double profit   = 0;

            for (int i = 0; i < n; i++)
            {
                int week      = weeksStart + i;
                int magaz     = weekMagStart + i;
                int nextMagaz = weekMagStart + i + 1;

                int    itemsProduced        = (int)flow.GetEdgeWeight(week, magaz);
                double weeklyProductionCost = production[i].Value;
                weeklyPlan[i].UnitsProduced = itemsProduced;
                profit -= weeklyProductionCost * itemsProduced;

                int itemsStored = 0;
                if (i <= n - 2)
                {
                    itemsStored = (int)flow.GetEdgeWeight(magaz, nextMagaz);
                    profit     -= itemsStored * storageInfo.Value;
                }

                weeklyPlan[i].UnitsSold   = new int[c];
                weeklyPlan[i].UnitsStored = itemsStored;
                for (int j = 0; j < c; j++)
                {
                    int contr = contrStart + j;

                    if (i == 0)
                    {
                        quantity += (int)flow.GetEdgeWeight(contr, target);
                    }

                    int    itemsSold = (int)flow.GetEdgeWeight(magaz, contr);
                    double price     = sales[j, i].Value;

                    profit += price * itemsSold;
                    weeklyPlan[i].UnitsSold[j] = itemsSold;
                }
            }

            return(new PlanData {
                Quantity = quantity, Value = profit
            });
        }
Exemplo n.º 9
0
        /// <summary>
        /// Część 2. zadania - zaplanowanie produkcji telewizorów dla wielu kontrahentów.
        /// </summary>
        /// <remarks>
        /// Do przeprowadzenia testów wyznaczających produkcję dającą maksymalny zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
        /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
        /// </remarks>
        /// <param name="production">
        /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza limit produkcji w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
        /// </param>
        /// <param name="sales">
        /// Dwuwymiarowa tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
        /// Pierwszy wymiar tablicy jest równy liczbie kontrahentów, zaś drugi - liczbie tygodni w planie.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
        /// Każdy wiersz tablicy odpowiada jednemu kontrachentowi.
        /// </param>
        /// <param name="storageInfo">
        /// Obiekt zawierający informacje o magazynie.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
        /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
        /// </param>
        /// <param name="weeklyPlan">
        /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
        /// </param>
        /// <returns>
        /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
        /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się optymalna liczba wyprodukowanych telewizorów,
        /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
        /// </returns>
        public PlanData CreateComplexPlan(PlanData[] production, PlanData[,] sales, PlanData storageInfo,
                                          out WeeklyPlan[] weeklyPlan)
        {
            weeklyPlan = null;
            if (!isOK(production, sales, storageInfo))
            {
                throw new ArgumentException();
            }

            int count = sales.GetLength(0); // count ilosc kotrahentow
            int n     = production.Length;  // n ilosc tygodni

            weeklyPlan = new WeeklyPlan[n];
            for (int i = 0; i < n; ++i)
            {
                weeklyPlan[i].UnitsSold = new int[count];
            }
            int source = n;
            int sink   = n + 1;
            int start  = n + 2;             // nr pierwszego kontrahenta
            int end    = start + count - 1; // nr ostatniego kontrahenta

            int V = 2 + count + n + n;

            int storageStart = end + 1;
            int storageEnd   = end + n;

            Graph g = new AdjacencyListsGraph <SimpleAdjacencyList>(true, V);
            Graph r = new AdjacencyListsGraph <SimpleAdjacencyList>(true, V);

            for (int i = start; i <= end; ++i)
            {
                // ujscie od kontrahenta
                g.AddEdge(i, sink, Double.MaxValue);//Double.MaxValue);
                r.AddEdge(i, sink, 0);
                // polaczenie sprzedazy kontrahentom
                int buyer = i - start;
                for (int tydzien = 0; tydzien < n; ++tydzien)
                {
                    g.AddEdge(storageStart + tydzien, i, sales[buyer, tydzien].Quantity);
                    r.AddEdge(storageStart + tydzien, i, -sales[buyer, tydzien].Value);
                }
            }
            for (int j = 0; j < n; ++j)
            {
                // dodanie produkcji (ze zrodla do tygodnia)
                g.AddEdge(source, j, production[j].Quantity);
                r.AddEdge(source, j, production[j].Value);
                // dodanie ujscia dla produkcji, ktorej sie nie oplaca produkowac
                g.AddEdge(j, sink, Double.MaxValue);
                r.AddEdge(j, sink, -production[j].Value);

                // dodanie krawedzi miedzy produkcja a wierzcholkiem kontrolujacym wyjscie do kontrahentow
                g.AddEdge(j, storageStart + j, production[j].Quantity);
                r.AddEdge(j, storageStart + j, 0);

                // dodanie magazynu
                if (j != n - 1) // bez ostatniego dnia bo wtedy nic nie magazynujemy
                {
                    g.AddEdge(storageStart + j, storageStart + j + 1, storageInfo.Quantity);
                    r.AddEdge(storageStart + j, storageStart + j + 1, storageInfo.Value);
                }
            }

            (double value, double cost, Graph flow)ret = MinCostFlowGraphExtender.MinCostFlow(g, r, source, sink, false, MaxFlowGraphExtender.PushRelabelMaxFlow, null, false);
            int    produced = 0;
            double profit   = 0;

            for (int i = 0; i < n; ++i)
            {
                // produkcja
                produced += weeklyPlan[i].UnitsProduced = production[i].Quantity - (int)ret.flow.GetEdgeWeight(i, sink);
                profit   -= weeklyPlan[i].UnitsProduced * production[i].Value;
                // sprzedaz
                for (int j = start; j <= end; ++j)
                {
                    weeklyPlan[i].UnitsSold[j - start] = (int)ret.flow.GetEdgeWeight(storageStart + i, j);
                    profit += ret.flow.GetEdgeWeight(storageStart + i, j) * (sales[j - start, i].Value); // (weeklyPlan[i].UnitsSold[j - start] * (sales[j - start, i].Value));
                }
                // magazyn
                if (i != n - 1)
                {
                    weeklyPlan[i].UnitsStored = (int)ret.flow.GetEdgeWeight(storageStart + i, storageStart + i + 1);
                    profit -= weeklyPlan[i].UnitsStored * storageInfo.Value;
                }
            }
            return(new PlanData {
                Quantity = produced, Value = Math.Ceiling(profit)
            });
        }
Exemplo n.º 10
0
        /// <summary>
        /// Część 2. zadania - zaplanowanie produkcji telewizorów dla wielu kontrahentów.
        /// </summary>
        /// <remarks>
        /// Do przeprowadzenia testów wyznaczających produkcję dającą maksymalny zysk wymagane jest jedynie zwrócenie obiektu <see cref="PlanData"/>.
        /// Testy weryfikujące plan wymagają przypisania tablicy z planem do parametru wyjściowego <see cref="weeklyPlan"/>.
        /// </remarks>
        /// <param name="production">
        /// Tablica obiektów zawierających informacje o produkcji fabryki w kolejnych tygodniach.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza limit produkcji w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - koszt produkcji jednej sztuki.
        /// </param>
        /// <param name="sales">
        /// Dwuwymiarowa tablica obiektów zawierających informacje o sprzedaży w kolejnych tygodniach.
        /// Pierwszy wymiar tablicy jest równy liczbie kontrahentów, zaś drugi - liczbie tygodni w planie.
        /// Wartości pola <see cref="PlanData.Quantity"/> oznaczają maksymalną sprzedaż w danym tygodniu,
        /// a pola <see cref="PlanData.Value"/> - cenę sprzedaży jednej sztuki.
        /// Każdy wiersz tablicy odpowiada jednemu kontrachentowi.
        /// </param>
        /// <param name="storageInfo">
        /// Obiekt zawierający informacje o magazynie.
        /// Wartość pola <see cref="PlanData.Quantity"/> oznacza pojemność magazynu,
        /// a pola <see cref="PlanData.Value"/> - koszt przechowania jednego telewizora w magazynie przez jeden tydzień.
        /// </param>
        /// <param name="weeklyPlan">
        /// Parametr wyjściowy, przez który powinien zostać zwrócony szczegółowy plan sprzedaży.
        /// </param>
        /// <returns>
        /// Obiekt <see cref="PlanData"/> opisujący wyznaczony plan.
        /// W polu <see cref="PlanData.Quantity"/> powinna znaleźć się optymalna liczba wyprodukowanych telewizorów,
        /// a w polu <see cref="PlanData.Value"/> - wyznaczony maksymalny zysk fabryki.
        /// </returns>
        public PlanData CreateComplexPlan(PlanData[] production, PlanData[,] sales, PlanData storageInfo,
                                          out WeeklyPlan[] weeklyPlan)
        {
            int weeks   = production.Length;
            int clients = sales.GetLength(0);

            if (weeks == 0 || clients == 0 || storageInfo.Quantity < 0 || storageInfo.Value < 0 || weeks != sales.GetLength(1))
            {
                throw new ArgumentException();
            }
            for (int i = 0; i < weeks; i++)
            {
                if (production[i].Quantity < 0 || production[i].Value < 0)
                {
                    throw new ArgumentException();
                }
                for (int clientNr = 0; clientNr < clients; clientNr++)
                {
                    if (sales[clientNr, i].Quantity < 0 || sales[clientNr, i].Value < 0)
                    {
                        throw new ArgumentException();
                    }
                }
            }

            Graph g = new AdjacencyListsGraph <HashTableAdjacencyList>(true, 2 * weeks + 1 + clients + 1);
            Graph c = g.IsolatedVerticesGraph();
            //weeks - weeks+clients-1 - clients
            //weeks+clients - source
            //weeks+clients + 1 - target

            int source            = weeks + clients;
            int target            = weeks + clients + 1;
            int storageStart      = weeks;
            int dummyStorageStart = weeks + clients + 2;

            for (int i = 0; i < weeks; i++)
            {
                g.AddEdge(source, dummyStorageStart + i, production[i].Quantity);
                c.AddEdge(source, dummyStorageStart + i, 0);

                g.AddEdge(dummyStorageStart + i, i, production[i].Quantity);
                c.AddEdge(dummyStorageStart + i, i, production[i].Value);

                g.AddEdge(dummyStorageStart + i, target, production[i].Quantity);
                c.AddEdge(dummyStorageStart + i, target, 0);

                for (int clientNr = 0; clientNr < clients; clientNr++)
                {
                    g.AddEdge(i, storageStart + clientNr, sales[clientNr, i].Quantity);
                    c.AddEdge(i, storageStart + clientNr, -sales[clientNr, i].Value);

                    g.AddEdge(storageStart + clientNr, target, double.MaxValue);
                    c.AddEdge(storageStart + clientNr, target, 0);
                }

                if (i < weeks - 1)
                {
                    g.AddEdge(i, i + 1, storageInfo.Quantity);
                    c.AddEdge(i, i + 1, storageInfo.Value);
                }
            }

            (double value, double cost, Graph flow) = g.MinCostFlow(c, source, target, true, MaxFlowGraphExtender.FordFulkersonDinicMaxFlow, MaxFlowGraphExtender.MKMBlockingFlow);

            for (int i = 0; i < weeks; i++)
            {
                value -= flow.GetEdgeWeight(dummyStorageStart + i, target);
            }

            weeklyPlan = new WeeklyPlan[weeks];
            for (int i = 0; i < weeks; i++)
            {
                weeklyPlan[i].UnitsProduced = (int)flow.GetEdgeWeight(dummyStorageStart + i, i);
                if (i < weeks - 1)
                {
                    weeklyPlan[i].UnitsStored = (int)flow.GetEdgeWeight(i, i + 1);
                }
                else
                {
                    weeklyPlan[i].UnitsStored = 0;
                }
                weeklyPlan[i].UnitsSold = new int[clients];
                for (int clientNr = 0; clientNr < clients; clientNr++)
                {
                    weeklyPlan[i].UnitsSold[clientNr] = (int)flow.GetEdgeWeight(i, weeks + clientNr);
                }
            }

            return(new PlanData {
                Quantity = (int)value, Value = -cost
            });
        }