예제 #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)
        {
            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
            });
        }
예제 #2
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
            });
        }
예제 #3
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   verticesPerWeek = 3;
            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);

                flowsGraph.AddEdge(week * verticesPerWeek + 2, week * verticesPerWeek + 3, sales[week].Quantity);
                costGraph.AddEdge(week * verticesPerWeek + 2, week * verticesPerWeek + 3, -sales[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);
                }

                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 SimpleWeeklyPlan[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
            });
        }
예제 #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)
        {
            //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
            });
        }