/// <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 }); }
/// <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 }); }
/// <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 }); }
/// <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 }); }