private static FractionedNumber[,] VogelFirstPart(FractionedNumber[,] costs, FractionedNumber[] demand, FractionedNumber[] supply) { verifyVogel(demand, supply, costs); Functions.result += "Matriz de custos de entrada:\n"; Functions.result += printMatrix(costs); Functions.result += "Supply de entrada:\n"; for(int i = 0;i < supply.Length;i++) { Functions.result += supply[i] + (i+1<supply.Length?", ":""); } Functions.result += "\nDemand de entrada:\n"; for(int i = 0;i < demand.Length;i++) { Functions.result += demand[i] + (i + 1 < demand.Length ? ", " : ""); } Functions.result += "\n----------------------------\n"; FractionedNumber[] demandRemaining = new FractionedNumber[demand.Length]; FractionedNumber[] supplyRemaining = new FractionedNumber[supply.Length]; FractionedNumber[,] result = new FractionedNumber[costs.GetLength(0), costs.GetLength(1)]; List<VogelPos> taxaDegeneracao = new List<VogelPos>(); Array.Copy(demand, demandRemaining, demand.Length); Array.Copy(supply, supplyRemaining, supply.Length); List<VogelPos> temp = new List<VogelPos>(); for (int l = 0; l < costs.GetLength(0); l++) { temp.Clear(); for (int c = 0; c < costs.GetLength(1); c++) { temp.Add(new VogelPos(l,c, costs[l, c],true)); } var n = temp.OrderBy(x => x.number); if(costs[n.ElementAt(0).x, n.ElementAt(0).y] < costs[n.ElementAt(1).x, n.ElementAt(1).y]) { taxaDegeneracao.Add(new VogelPos(n.ElementAt(0).x, n.ElementAt(0).y, n.ElementAt(1).number - n.ElementAt(0).number,true)); } else { taxaDegeneracao.Add(new VogelPos(n.ElementAt(1).x, n.ElementAt(1).y, n.ElementAt(0).number - n.ElementAt(1).number,true)); } } for(int c = 0;c < costs.GetLength(1);c++) { temp.Clear(); for(int l = 0;l < costs.GetLength(0);l++) { temp.Add(new VogelPos(l, c, costs[l, c],false)); } temp = temp.OrderBy(x => x.number).ToList(); if(costs[temp.ElementAt(0).x, temp.ElementAt(0).y] < costs[temp.ElementAt(1).x, temp.ElementAt(1).y]) { taxaDegeneracao.Add(new VogelPos(temp.ElementAt(0).x, temp.ElementAt(0).y, temp.ElementAt(1).number - temp.ElementAt(0).number,false)); } else { taxaDegeneracao.Add(new VogelPos(temp.ElementAt(1).x, temp.ElementAt(1).y, temp.ElementAt(0).number - temp.ElementAt(1).number,false)); } } Functions.result += "Taxa de degeneração: \n"; for(int i = 0;i < taxaDegeneracao.Count;i++) { Functions.result += taxaDegeneracao[i].number + " @ " + (taxaDegeneracao[i].x + 1) + "," + (taxaDegeneracao[i].y + 1) + (taxaDegeneracao[i].line?" linha ":" coluna ") + "\n"; } Functions.result += "---------- \n"; taxaDegeneracao = taxaDegeneracao.OrderBy(x => 0-x.number).ThenBy(x=>costs[x.x,x.y]).ToList(); Functions.result += "Taxa de degeneração ordenada: \n"; for(int i = 0;i < taxaDegeneracao.Count;i++) { Functions.result += taxaDegeneracao[i].number + " @ " + (taxaDegeneracao[i].x + 1) + "," + (taxaDegeneracao[i].y + 1) + (taxaDegeneracao[i].line ? " linha " : " coluna ") + "\n"; } Functions.result += "---------- \n"; //Respeita a ordem da taxa de degeneracao for(int i = 0;i < taxaDegeneracao.Count;i++) { int l = taxaDegeneracao[i].x; int c = taxaDegeneracao[i].y; FractionedNumber min = long.MaxValue; FractionedNumber minSupplyDemand; if(taxaDegeneracao[i].line) { for(int j = 0;j < costs.GetLength(1);j++) { if(costs[l, j] < min) { if(supply[l] > 0 && demand[j] > 0) { min = costs[l, j]; c = j; } } } } else { for(int j = 0;j < costs.GetLength(0);j++) { if(costs[j, c] < min) { if(supply[j] > 0 && demand[c] > 0) { min = costs[j, c]; l = j; } } } } if(supply[l] == 0 || demand[c] == 0) continue; minSupplyDemand = FractionedNumber.Min(supply[l], demand[c]); supply.SetValue(supply.ElementAt(l) - minSupplyDemand, l); demand.SetValue(demand.ElementAt(c) - minSupplyDemand, c); result[l, c] = minSupplyDemand; } temp.Clear(); for(int l = 0;l < costs.GetLength(0);l++) { for(int c = 0;c < costs.GetLength(1);c++) { temp.Add(new VogelPos(l, c, costs[l, c],false)); } } temp = temp.OrderBy(x => x.number).ToList(); for(int i = 0;i < temp.Count;i++) { if(supply[temp[i].x] > 0) { if(demand[temp[i].y] > 0){ FractionedNumber min = FractionedNumber.Min(supply[temp[i].x], demand[temp[i].y]); result[temp[i].x, temp[i].y] = min; supply[temp[i].x] -= min; demand[temp[i].y] -= min; } } } Functions.result += "Matriz antes de fazer a segunda parte:\n"; Functions.result += printMatrix(result); Functions.result += "-------------------------------\n"; return result; }
private static FractionedNumber[,] VogelSecondPart(FractionedNumber[,] costs, FractionedNumber[] demand, FractionedNumber[] supply, FractionedNumber[,] matrix) { VogelPos min; int count = 1; do { min = new VogelPos(-1, -1, long.MaxValue, false); FractionedNumber[,] res = new FractionedNumber[matrix.GetLength(0), matrix.GetLength(1)]; bool[,] usedMatrix = GetMatrixInsideVogel(matrix); bool[,] usedMatrix2 = new bool[usedMatrix.GetLength(0), usedMatrix.GetLength(1)]; System.Array.Copy(usedMatrix, usedMatrix2, usedMatrix.Length); FractionedNumber[,] tempMatrix = new FractionedNumber[matrix.GetLength(0), matrix.GetLength(1)]; Functions.result += "=============================\n"; Functions.result += "Iteração "+count+"\n"; Functions.result += "=============================\n"; FractionedNumber[] lines = new FractionedNumber[matrix.GetLength(0)]; FractionedNumber[] colums = new FractionedNumber[matrix.GetLength(1)]; goLine(-1, -1, 0, tempMatrix, costs, usedMatrix2, lines, colums); bool erroL = false; bool erroC = false; for(int i = 0;i < lines.Length;i++) { if(lines[i] == null) erroL = true; } for(int i = 0;i < colums.Length;i++) { if(colums[i] == null) erroC = true; } if(erroL || erroC) { min.number = -1; Functions.result += "=============================\n"; Functions.result += "Não foi possível colocar valores em todas as linhas e colunas.\n"; Functions.result += "Deve-se criar uma variável artificial.\n"; int posX = -1; int posY = -1; if(erroL){ for(int i = 0;i < lines.Length;i++) { if(lines[i] == null) { for(int j = 0;j < matrix.GetLength(1);j++) { if(matrix[i, j] == null) { posX = i; posY = j; break; } } break; } } } else { for(int i = 0;i < colums.Length;i++) { if(colums[i] == null) { for(int j = 0;j < matrix.GetLength(0);j++) { if(matrix[j, i] == null) { posX = i; posY = j; break; } } break; } } } matrix[posX, posY] = 0; Functions.result += "Ela foi colocada em: L"+(posX+1)+", C"+(posY+1)+"\n"; Functions.result += "=============================\n"; continue; } for(int i = 0;i < lines.Length;i++) { Functions.result += "L" + (i + 1) + ":" + lines[i] + ", \t"; } Functions.result += "\n"; for(int i = 0;i < colums.Length;i++) { Functions.result += "C" + (i + 1) + ":" + colums[i] + ", \t"; ; } Functions.result += "\n\n"; Functions.result += "Matriz dentro:\n"; Functions.result += printMatrix(tempMatrix); Functions.result += "-------------------------\n"; sumOut(lines, colums, usedMatrix, costs, tempMatrix); Functions.result += "Matriz fora:\n"; Functions.result += printMatrix(tempMatrix); Functions.result += "-------------------------\n"; for(int l = 0;l < tempMatrix.GetLength(0);l++) { for(int c = 0;c < tempMatrix.GetLength(1);c++) { if(tempMatrix[l, c] != null) { if(tempMatrix[l, c] < min.number) { min.y = c; min.x = l; min.number = tempMatrix[l, c]; } } } } Functions.result += "Valor mínimo: "+min.number+" na linha "+(min.x+1)+" e coluna "+(min.y+1)+"\n"; if(min.number < 0) { List<VogelPos> list = VogelFindWay(min, usedMatrix, matrix); if(list == null) break; FractionedNumber min2 = FractionedNumber.Min(list[0].number, list[list.Count - 1].number); Functions.result += "Minimo: " + min2 + "\n"; bool soma = false; for(int i = 0;i < list.Count;i++) { if(matrix[list[i].x, list[i].y] == null) matrix[list[i].x, list[i].y] = 0; if(soma) { matrix[list[i].x, list[i].y] += min2; } else { matrix[list[i].x, list[i].y] -= min2; } if(matrix[list[i].x, list[i].y] == 0) matrix[list[i].x, list[i].y] = null; soma = !soma; } matrix[min.x, min.y] += min2; Functions.result += "Fez a troca\n"; } Functions.result += "-------------------------\n"; Functions.result += "Matriz: \n"; Functions.result += "-------------------------\n"; Functions.result += printMatrix(matrix); Functions.result += "-------------------------\n"; count++; } while(min.number<0 && count <= 25); if(count > 20) { Functions.result += "***********************\n"; Functions.result += "Houve muitas iterações, algo está errado!\n"; Functions.result += "***********************\n"; } bool tirouArt = false; for(int l = 0;l < matrix.GetLength(0);l++) { for(int c = 0;c < matrix.GetLength(1);c++) { if(matrix[l, c] == 0) { matrix[l, c] = null; tirouArt = true; } } } if(tirouArt) { Functions.result += "Foram tiradas as variáveis artificiais, ficando assim:\n"; Functions.result += printMatrix(matrix); Functions.result += "-------------------------\n"; } return matrix; }
private static void verifyVogel(FractionedNumber[] demand, FractionedNumber[] supply, FractionedNumber[,] matrix) { if(matrix.GetLength(1) != demand.Length || matrix.GetLength(0) != supply.Length) { string msg = "The demand and supply array doesn't have the same size of the matix\n"; msg += "demand["+demand.Length+"], supply["+supply.Length+"], costs["+matrix.GetLength(0)+","+matrix.GetLength(1)+"]"; throw new Exception(msg); } FractionedNumber sumSupply = SumNumbers(supply); FractionedNumber sumDemand = SumNumbers(demand); if(sumSupply != sumDemand) { string msg = "The sums of the supply and demand are differents!\n"; msg += "Supply sum: " + sumSupply + ", Demand sum: " + sumDemand+"\n"; msg += "You need to insert a new "; if(sumSupply > sumDemand) msg += "demand (row bellow)"; else msg += "supply (colum on right)"; msg += " with the value " + (FractionedNumber.Max(sumDemand, sumSupply) - FractionedNumber.Min(sumDemand, sumSupply)); throw new Exception(msg); } }
private static FractionedNumber VogelCalculateTotalCost(FractionedNumber[,] matrix, FractionedNumber[,] costs) { result += "Total cost: "; FractionedNumber sum = 0; for(int l = 0;l < matrix.GetLength(0);l++) { for(int c = 0;c < matrix.GetLength(1);c++) { sum += matrix[l, c] * costs[l, c]; } } result += sum; result += "\n"; return sum; }
private static string printMatrix(FractionedNumber[,] m) { string s = ""; for(int l = 0;l < m.GetLength(0);l++) { for(int c = 0;c < m.GetLength(1);c++) { s += (m[l, c] + "\t|"); } s += "\n"; } return s; }
private static void sumOut(FractionedNumber[] lines, FractionedNumber[] colums, bool[,] usedMatrix, FractionedNumber[,] costs, FractionedNumber[,] tempMatrix) { for(int l = 0;l < tempMatrix.GetLength(0);l++) { for(int c = 0;c < tempMatrix.GetLength(1);c++) { if(!usedMatrix[l, c]) { tempMatrix[l, c] = costs[l, c] - lines[l] - colums[c]; } else { tempMatrix[l, c] = null; } } } }
private static FractionedNumber[,] NorthWestFirstPart(FractionedNumber[,] costs, FractionedNumber[] demand, FractionedNumber[] supply) { verifyVogel(demand, supply, costs); Functions.result += "Matriz de custos de entrada:\n"; Functions.result += printMatrix(costs); Functions.result += "Supply de entrada:\n"; for(int i = 0;i < supply.Length;i++) { Functions.result += supply[i] + (i + 1 < supply.Length ? ", " : ""); } Functions.result += "\nDemand de entrada:\n"; for(int i = 0;i < demand.Length;i++) { Functions.result += demand[i] + (i + 1 < demand.Length ? ", " : ""); } Functions.result += "\n----------------------------\n"; FractionedNumber[] demandRemaining = new FractionedNumber[demand.Length]; FractionedNumber[] supplyRemaining = new FractionedNumber[supply.Length]; FractionedNumber[,] result = new FractionedNumber[costs.GetLength(0), costs.GetLength(1)]; Array.Copy(demand, demandRemaining, demand.Length); Array.Copy(supply, supplyRemaining, supply.Length); int posL = 0; int posC = 0; while(demandRemaining[posC]!=0 && supplyRemaining[posL]!=0) { FractionedNumber min = FractionedNumber.Min(demandRemaining[posC], supplyRemaining[posL]); result[posL, posC] = min; demandRemaining[posC] -= min; supplyRemaining[posL] -= min; if(supplyRemaining[posL] == 0) { if(supplyRemaining.Length!=posL+1) posL++; } if(demandRemaining[posC] == 0) { if(demandRemaining.Length != posC + 1) posC++; } } Functions.result += "Matriz antes de fazer a segunda parte:\n"; Functions.result += printMatrix(result); Functions.result += "-------------------------------\n"; return result; }
private static void goLine(int x, int y, FractionedNumber v, FractionedNumber[,] m, FractionedNumber[,] costs, bool[,] usedMatrix, FractionedNumber[] lines, FractionedNumber[] colums) { if(x == -1 && y == -1) { lines[0] = 0; } for(int i = 0;i < m.GetLength(1);i++) { if(i == y) continue; if((x == -1 && y == -1) || usedMatrix[x,i]) { if(x == -1 && y == -1) { if(usedMatrix[0, i]) { m[0, i] = 0 - v + costs[0, i]; if(colums[i] == null) colums[i] = m[0, i]; usedMatrix[0, i] = false; goColum(0, i, m[0, i], m, costs, usedMatrix, lines, colums); } } else { m[x, i] = 0 - v + costs[x, i]; if(colums[i] == null) colums[i] = m[x, i]; usedMatrix[x, i] = false; goColum(x, i, m[x, i], m, costs, usedMatrix, lines, colums); } } } }
private static void goColum(int x, int y, FractionedNumber v, FractionedNumber[,] m, FractionedNumber[,] costs, bool[,] usedMatrix, FractionedNumber[] lines, FractionedNumber[] colums) { for(int i = 0;i < m.GetLength(0);i++) { if(i == x) continue; if(usedMatrix[i,y]) { m[i,y] = 0 - v + costs[i,y]; if(lines[i] == null) lines[i] = m[i, y]; usedMatrix[i,y] = false; goLine(i,y, m[i,y], m, costs, usedMatrix, lines, colums); } } }
private static bool[,] GetMatrixInsideVogel(FractionedNumber[,] matrix) { bool[,] res = new bool[matrix.GetLength(0), matrix.GetLength(1)]; for (int l = 0; l < matrix.GetLength(0); l++) { for (int c = 0; c < matrix.GetLength(1); c++) { if (matrix[l, c] != null) res[l, c] = true; else res[l, c] = false; } } return res; }
public static FractionedNumber[,] VogelInverseMatrix(FractionedNumber[,] matrix) { FractionedNumber max = long.MinValue; FractionedNumber[,] newMatrix = new FractionedNumber[matrix.GetLength(0), matrix.GetLength(1)]; for(int l = 0;l < matrix.GetLength(0);l++) { for(int c = 0;c < matrix.GetLength(1);c++) { max = FractionedNumber.Max(max, matrix[l, c]); } } for(int l = 0;l < matrix.GetLength(0);l++) { for(int c = 0;c < matrix.GetLength(1);c++) { newMatrix[l, c] = max - matrix[l, c]; } } return newMatrix; }