private void runModel(List <Employee> employees, List <Shift> shifts) { StreamWriter writer = File.CreateText(@"C:\Users\user\Desktop\cplex log\result9.txt"); try { Cplex model = new Cplex(); model.SetOut(writer); //------------------------------ //---Variable initialization----- //------------------------------ //Assignment variables IDictionary <string, IIntVar> assignVars = new Dictionary <string, IIntVar>(); employees.ForEach(employee => { shifts.ForEach(shift => { string name = getAssignVarName(employee, shift); assignVars.Add(name, model.BoolVar(name)); }); }); //Total assignment hours INumVar totalAssignHourVar = model.NumVar(0, Double.MaxValue, getTotalAssignVarName()); //---------------------------------- //---Constraints initialization----- //----------------------------------- //1) Min rest constraint //2) Goal total assigned hours constraint ILinearNumExpr sumAssignHourExpr = model.LinearNumExpr(); sumAssignHourExpr.AddTerm(-1.0, totalAssignHourVar); employees.ForEach(employee => { shifts.ForEach(shift1 => { ILinearNumExpr sumOverlapExpr = model.LinearNumExpr(); string name1 = getAssignVarName(employee, shift1); IIntVar assignVar1 = assignVars[name1]; sumOverlapExpr.AddTerm(1.0, assignVar1); shifts.ForEach(shift2 => { if (shift1 != shift2 && this.isDurationOverlap(shift1, shift2)) { string name2 = getAssignVarName(employee, shift2); sumOverlapExpr.AddTerm(1.0, assignVars[name2]); } }); model.AddLe(sumOverlapExpr, 1.0, "MinRestConst"); sumAssignHourExpr.AddTerm((shift1.end - shift1.begin).TotalMinutes, assignVar1); }); }); //3) No overassignment constraint shifts.ForEach(shift => { ILinearNumExpr sumAssigsExpr = model.LinearNumExpr(); employees.ForEach(employee => { string name1 = getAssignVarName(employee, shift); IIntVar assignVar1 = assignVars[name1]; sumAssigsExpr.AddTerm(1.0, assignVar1); }); model.AddLe(sumAssigsExpr, shift.shiftNumber, "NoOverAssignConst"); }); model.AddEq(sumAssignHourExpr, 0.0, "TotalAssignedHourConst"); INumVar[] goalVars = { totalAssignHourVar }; double[] coeffs = { 1.0 }; model.AddMaximize(model.ScalProd(goalVars, coeffs)); model.ExportModel(@"C:\Users\user\Desktop\cplex log\model1.lp"); bool feasible = model.Solve(); if (feasible) { double objVal = model.ObjValue; model.Output().WriteLine("Solution value = " + model.ObjValue); shifts.ForEach(shift => { ILinearNumExpr sumAssigsExpr = model.LinearNumExpr(); employees.ForEach(employee => { string name = getAssignVarName(employee, shift); }); model.AddLe(sumAssigsExpr, shift.shiftNumber, "NoOverAssignConst"); }); } else { } } catch (System.Exception ex) { Response.ContentType = "application/json; charset=utf-8"; Response.Write(ex.Message); Response.End(); } writer.Close(); }
/// <summary> /// return a list of words that can be played, left over letters are the last word /// </summary> /// <param name="chips">All of the chips to conisder, first ones are on the board</param> /// <param name="numberOnBoard">The number of leading chips are on the board already</param> /// <returns></returns> public static List <Chip[]> Solve(List <Chip> chips, int numberOnBoard, bool suppress = true) { if (chips == null || chips.Count == 0) { Utility.Warning("Chips is null or empty!"); return(null); } int chip_count = chips.Count; int word_count = chip_count / 3 + 1; Cplex model = new Cplex(); IIntVar[] X = model.BoolVarArray(chip_count); // should we place the ith chip IIntVar[][] Y = new IIntVar[chip_count][]; // which word do we place the ith chip on IIntVar[] WO = model.BoolVarArray(word_count); // flag for if the jth word is an order word or not IIntVar[] WC = model.BoolVarArray(word_count); // flag for if the jth word is a color word or not IIntVar[] WN = model.BoolVarArray(word_count); // flag for if the jth word is not used or is used IIntVar[][] UO = new IIntVar[word_count][]; // what is the number associated with this word (used only if a color word) IIntVar[][] UC = new IIntVar[word_count][]; // what is the color associated with this word (used only if a order word) IIntVar[][] PC = new IIntVar[word_count][]; // if i maps to word j and j is a color word, this will be 1 at [j][i] IIntVar[][] PO = new IIntVar[word_count][]; // if i maps to word j and j is a order word, this will be 1 at [j][i] (if and only if) // Initialize for (int i = 0; i < chip_count; i++) { Y[i] = model.BoolVarArray(word_count); } for (int i = 0; i < word_count; i++) { UC[i] = model.BoolVarArray(Chip.COLORCOUNT); } for (int i = 0; i < word_count; i++) { UO[i] = model.BoolVarArray(Chip.NUMBERCOUNT); } for (int i = 0; i < word_count; i++) { PC[i] = model.BoolVarArray(chip_count); } for (int i = 0; i < word_count; i++) { PO[i] = model.BoolVarArray(chip_count); } // for each word which chips map to it IIntVar[][] Yt = new IIntVar[word_count][]; for (int i = 0; i < word_count; i++) { Yt[i] = new IIntVar[chip_count]; for (int j = 0; j < chip_count; j++) { Yt[i][j] = Y[j][i]; } } // maximize the number of placed chips model.AddMaximize(model.Sum(X)); // if we place i, we need to map it to some word for (int i = 0; i < chip_count; i++) { model.AddLe(X[i], model.Sum(Y[i])); } // we can map to at most 1 value for (int i = 0; i < chip_count; i++) { model.AddLe(model.Sum(Y[i]), 1); } // if any chip maps to word j, turn the not used flag off for (int j = 0; j < word_count; j++) { for (int i = 0; i < chip_count; i++) { model.AddLe(Y[i][j], model.Diff(1, WN[j])); } } // if a word is used, make sure it has at least 3 chips for (int j = 0; j < word_count; j++) { model.AddLe(model.Prod(3, model.Diff(1, WN[j])), model.Sum(Yt[j])); } // first 'numberOnBoard' chips are on the board and thus must be placed for (int i = 0; i < numberOnBoard; i++) { model.AddEq(X[i], 1); } // each word is either an order word or a color word for (int i = 0; i < word_count; i++) { model.AddEq(model.Sum(WO[i], WC[i], WN[i]), 1); } // if i maps to word j and j is a color word make sure PC[j][i] is 1 for (int j = 0; j < word_count; j++) { for (int i = 0; i < chip_count; i++) { model.AddGe(model.Sum(1, PC[j][i]), model.Sum(WC[j], Y[i][j])); } } // if i maps to word j and j is a order word, PO will be 1 at [j][i] (if and only if) for (int j = 0; j < word_count; j++) { for (int i = 0; i < chip_count; i++) { model.AddGe(model.Sum(1, PO[j][i]), model.Sum(WO[j], Y[i][j])); model.AddLe(PO[j][i], WO[j]); model.AddLe(PO[j][i], Y[i][j]); } } // ************************************************ // ************ TYPE CONSTRAINTS ****************** // ************************************************ for (int i = 0; i < chip_count; i++) { for (int j = 0; j < word_count; j++) { // if this is a color word and a chip maps to it then the numbers of each chip on this word must match for (int k = 0; k < Chip.NUMBERCOUNT; k++) { var bnd = model.Sum(WO[j], model.Diff(1, Y[i][j])); model.AddLe(model.Diff(UO[j][k], chips[i].number[k] ? 1 : 0), bnd); model.AddLe(model.Diff(chips[i].number[k] ? 1 : 0, UO[j][k]), bnd); } // if this is a order word and a chip maps to it then the colors of each chip on this word must match for (int k = 0; k < Chip.COLORCOUNT; k++) { var bnd = model.Sum(WC[j], model.Diff(1, Y[i][j])); model.AddLe(model.Diff(UC[j][k], chips[i].color[k] ? 1 : 0), bnd); model.AddLe(model.Diff(chips[i].color[k] ? 1 : 0, UC[j][k]), bnd); } } } // if this is a color word, ensure that at most one of each color is allowed for (int j = 0; j < word_count; j++) { for (int k = 0; k < Chip.COLORCOUNT; k++) { int[] colstack = new int[chip_count]; for (int i = 0; i < chip_count; i++) { colstack[i] = chips[i].color[k] ? 1 : 0; } model.Add(model.IfThen(model.Eq(WC[j], 1), model.Le(model.ScalProd(colstack, PC[j]), 1))); } } // ensure that the numbers in an order word are sequential for (int j = 0; j < word_count; j++) { IIntVar[] V = model.BoolVarArray(Chip.NUMBERCOUNT); for (int k = 0; k < Chip.NUMBERCOUNT; k++) { int[] numstack = new int[chip_count]; for (int i = 0; i < chip_count; i++) { numstack[i] = chips[i].number[k] ? 1 : 0; } // if this is an order word put the binary numbers into a vector of flags for those numbers model.Add(model.IfThen(model.Eq(WO[j], 1), model.Eq(model.ScalProd(numstack, PO[j]), V[k]))); } // for each number either the next flag is strictly larger, meaning the start of the sequence // or every flag after a decrease is 0, the end of a sequence for (int i = 0; i < Chip.NUMBERCOUNT - 1; i++) { IIntVar Z = model.BoolVar(); model.AddLe(model.Diff(V[i], V[i + 1]), Z); for (int k = i + 1; k < Chip.NUMBERCOUNT; k++) { model.AddLe(V[k], model.Diff(1, Z)); } } } List <Chip[]> words = new List <Chip[]>(); if (suppress) { model.SetOut(null); } Utility.Log("Thinking..."); if (model.Solve()) { for (int j = 0; j < word_count; j++) { if (model.GetValue(WN[j]) > 0.5) { continue; } List <Chip> word = new List <Chip>(); double[] flags = model.GetValues(Yt[j]); for (int i = 0; i < chip_count; i++) { if (flags[i] > 0.5) { word.Add(chips[i]); } } // if this is a color word else it is an order word if (model.GetValue(WC[j]) > 0.5) { words.Add(word.OrderBy(p => Array.IndexOf(p.color, true)).ToArray()); } else { words.Add(word.OrderBy(p => Array.IndexOf(p.number, true)).ToArray()); } } } else { Utility.Warning("No possible moves found!"); } model.Dispose(); Chip[] notplayed = chips.Where(p => !words.Any(q => q.Contains(p))).ToArray(); words.Add(notplayed); return(words); }
/// <summary> /// Getting maximum congruency for naming parameter sets A or B. Linear Programming optimization model. /// Eq. (4) and Table II in DOI:10.1109/CEC.2019.8790261 /// The matrices need to be manually entered here in the script (cTopA, cTopB, cBtmA, cBtmB) /// </summary> internal static void IdentifyTwoBestParameterSets(string caseSolver) { Cplex cpl = new Cplex(); int N = 7; //string caseSolver = "ES"; //"SGA" (default), "ES", "PSO", "FIPS" int[] cTopA; int[] cTopB; int[] cBtmA; int[] cBtmB; switch (caseSolver) { default: cTopA = new int[] { 11, 1, 1, 13, 0, 0, 2 }; cTopB = new int[] { 0, 5, 3, 0, 5, 5, 5 }; cBtmA = new int[] { 2, 12, 12, 0, 14, 14, 9 }; cBtmB = new int[] { 4, 0, 1, 4, 0, 0, 0 }; break; case "ES": cTopA = new int[] { 4, 6, 9, 3, 11, 11, 5 }; cTopB = new int[] { 2, 3, 1, 3, 1, 3, 3 }; cBtmA = new int[] { 4, 5, 2, 8, 0, 0, 6 }; cBtmB = new int[] { 3, 1, 3, 2, 5, 3, 2 }; break; case "PSO": cTopA = new int[] { 1, 3, 2, 3, 3, 7, 5 }; cTopB = new int[] { 12, 11, 3, 1, 7, 8, 5 }; cBtmA = new int[] { 7, 5, 6, 5, 5, 1, 3 }; cBtmB = new int[] { 0, 1, 9, 11, 5, 4, 7 }; break; case "FIPS": cTopA = new int[] { 6, 6, 7, 3, 5, 0, 8 }; cTopB = new int[] { 4, 6, 6, 9, 5, 9, 1 }; cBtmA = new int[] { 4, 4, 3, 7, 5, 10, 2 }; cBtmB = new int[] { 6, 4, 4, 1, 5, 1, 9 }; break; } INumVar[] xTopA = new INumVar[N]; INumVar[] xBtmB = new INumVar[N]; INumVar[] xTopB = new INumVar[N]; INumVar[] xBtmA = new INumVar[N]; ILinearNumExpr value = cpl.LinearNumExpr(); for (int n = 0; n < N; n++) { xTopA[n] = cpl.BoolVar(); xBtmB[n] = cpl.BoolVar(); xTopB[n] = cpl.BoolVar(); xBtmA[n] = cpl.BoolVar(); cpl.AddEq(cpl.Sum(xTopB[n], xTopA[n]), 1); cpl.AddEq(cpl.Sum(xBtmA[n], xBtmB[n]), 1); cpl.AddEq(cpl.Sum(xTopA[n], xBtmA[n]), 1); cpl.AddEq(cpl.Sum(xTopB[n], xBtmB[n]), 1); value.AddTerm(xTopA[n], cTopA[n]); value.AddTerm(xTopB[n], cTopB[n]); value.AddTerm(xBtmA[n], cBtmA[n]); value.AddTerm(xBtmB[n], cBtmB[n]); } cpl.AddMaximize(value); cpl.Solve(); Console.WriteLine("Parameter Grouping for Solver: {0}", caseSolver); for (int n = 0; n < N; n++) { Console.WriteLine("n: {0}", n); Console.WriteLine("xtopA: ;{0};, _____, xTopB: ;{1};", cpl.GetValue(xTopA[n]), cpl.GetValue(xTopB[n])); Console.WriteLine("xbtmB: ;{0};, _____, xBtmA: ;{1};", cpl.GetValue(xBtmB[n]), cpl.GetValue(xBtmA[n])); } Console.WriteLine("cost: {0}", cpl.GetObjValue()); Console.ReadKey(); }
private double one_tsp(int dim, int [][] matrix, int [] path) { int[] lo = new int[dim]; for (int i = 0; i < dim; i++) { lo[i] = 1; } Cplex cplex = new Cplex(); NumVarType varType = NumVarType.Bool; INumVar[][] x = new INumVar[dim][]; for (int i = 0; i < dim; i++) { x[i] = cplex.NumVarArray(dim, 0, 1); } for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { x[i][j] = cplex.BoolVar(); } } for (int j = 0; j < dim; j++) { INumExpr xcolSum = cplex.NumExpr(); for (int i = 0; i < dim; i++) { xcolSum = cplex.Sum(xcolSum, x[i][j]); } cplex.AddEq(lo[j], xcolSum); } varType = NumVarType.Float; INumVar[] u = new INumVar[dim]; for (int j = 0; j < dim; j++) { u[j] = cplex.NumVar(0, 100000); } for (int j = 1; j < dim; j++) { cplex.AddGe(u[j], 0); } for (int i = 1; i < dim; i++) { for (int j = 1; j < dim; j++) { if (i != j) { cplex.AddLe(cplex.Sum(cplex.Diff(u[i], u[j]), cplex.Prod(dim, x[i][j])), dim - 1); } } } for (int i = 0; i < dim; i++) { INumExpr xrowSum = cplex.NumExpr(); for (int j = 0; j < dim; j++) { xrowSum = cplex.Sum(xrowSum, x[i][j]); } cplex.AddEq(lo[i], xrowSum); } INumExpr costSum = cplex.NumExpr(); for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { costSum = cplex.Sum(costSum, cplex.Prod(x[i][j], matrix[i][j])); } } cplex.AddMinimize(costSum); try { if (cplex.Solve()) { //MessageBox.Show("Solution status = " + cplex.GetStatus()); //MessageBox.Show("cost = " + cplex.ObjValue); int ipath = 0; int depo = -1; for (int i = dim - 1; i >= 0; i--) { for (int j = 0; j < dim; j++) { if (Convert.ToInt16(cplex.GetValue(x[i][j])) == 1) { depo = i; } } } path[ipath] = depo; ipath++; while (depo > -1) { for (int j = 0; j < dim; j++) { if (Convert.ToInt16(cplex.GetValue(x[path[ipath - 1]][j])) == 1) { path[ipath] = j; ipath++; if (j == depo) { depo = -1; } break; } } } return(cplex.ObjValue); } cplex.End(); } catch (ILOG.Concert.Exception ex) { System.Console.WriteLine("Concert Error: " + ex); } return(-1); }
private void decomp(int dim, int kts, int[][] dist, List <int> WorkList) { int[] lo = new int[dim]; int dk = dim * kts; for (int i = 0; i < dim; i++) { lo[i] = 1; } Cplex cplex = new Cplex(); NumVarType varType = NumVarType.Bool; INumVar[][] x = new INumVar[dim][]; for (int i = 0; i < dim; i++) { x[i] = cplex.NumVarArray(dk, 0, 1); } for (int i = 0; i < dim; i++) { for (int j = 0; j < dk; j++) { x[i][j] = cplex.BoolVar(); } } //**************************************** //Что тут происходит? for (int j = 0; j < dim; j++) { INumExpr xcolSum = cplex.NumExpr(); for (int k = 0; k < kts; k++) { for (int i = 0; i < dim; i++) { xcolSum = cplex.Sum(xcolSum, x[i][k * dim + j]); } } cplex.AddEq(lo[j], xcolSum); } varType = NumVarType.Float; INumVar[] u = new INumVar[dk]; for (int j = 0; j < dk; j++) { u[j] = cplex.NumVar(0, 100000); } for (int j = 1; j < dk; j++) { cplex.AddGe(u[j], 0); } for (int k = 0; k < kts; k++) { for (int i = 1; i < dim; i++) { for (int j = 1; j < dim; j++) { if (i != j) { if (kts == 1) { cplex.AddLe(cplex.Sum(cplex.Diff(u[k * dim + i], u[k * dim + j]), cplex.Prod(dim, x[i][k * dim + j])), dim - 1); } else { cplex.AddLe(cplex.Sum(cplex.Diff(u[k * dim + i], u[k * dim + j]), cplex.Prod(dim, x[i][k * dim + j])), dim); } } } } } for (int i = 0; i < dim; i++) { INumExpr xrowSum = cplex.NumExpr(); for (int j = 0; j < dk; j++) { xrowSum = cplex.Sum(xrowSum, x[i][j]); } cplex.AddEq(lo[i], xrowSum); } //Условия независимости кластеров if (kts > 1) { int[] a = new int[kts + 1]; for (int k = 1; k < kts; k++) { if (k > 1 && k < kts - 1) { continue; } int p; for (int i = 1; i <= k; i++) { a[i] = i; } p = k; while (p >= 1) { for (int m = 0; m < dim; m++) { INumExpr xcolrowSum = cplex.NumExpr(); for (int j = 1; j <= kts; j++) { bool row = false; for (int i = 1; i <= k; i++) { if (a[i] == j) { row = true; } } if (row) { for (int t = 0; t < dim; t++) { xcolrowSum = cplex.Sum(xcolrowSum, x[m][(j - 1) * dim + t]); } } else { for (int t = 0; t < dim; t++) { xcolrowSum = cplex.Sum(xcolrowSum, x[t][(j - 1) * dim + m]); } } } cplex.AddLe(xcolrowSum, lo[m]); } if (a[k] == kts) { p--; } else { p = k; } if (p >= 1) { for (int i = k; i >= p; i--) { a[i] = a[p] + i - p + 1; } } } } } INumExpr costSum = cplex.NumExpr(); INumExpr[] costSum1 = new INumExpr[kts]; if (kts == 1) { for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { costSum = cplex.Sum(costSum, cplex.Prod(x[i][j], dist[i][j])); } } cplex.AddMinimize(costSum); } else { for (int k = 0; k < kts; k++) { costSum1[k] = cplex.NumExpr(); for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { costSum1[k] = cplex.Sum(costSum1[k], cplex.Prod(x[i][k * dim + j], dist[i][j])); } } //cplex.AddLe(costSum1[k], costSum); } costSum = cplex.Max(costSum1); cplex.AddMinimize(costSum); } try { if (cplex.Solve()) { textBox1.Text += "lambda = " + cplex.ObjValue + Environment.NewLine; textBox1.Text += DateTime.Now.ToString() + Environment.NewLine; WorkList.Clear(); int num_clust = 0; for (int k = 0; k < kts; k++) { int dim1 = 0; for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { if (Convert.ToInt16(cplex.GetValue(x[i][k * dim + j])) == 1) { dim1++; } } } if (dim1 > 0) { num_clust++; for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { if (Convert.ToInt16(cplex.GetValue(x[i][k * dim + j])) == 1) { WorkList.Add(i); break; } } } WorkList.Add(-1); } } textBox1.Text += DateTime.Now.ToString() + Environment.NewLine; } else { textBox1.Text += "Нет решения" + Environment.NewLine; textBox1.Text += DateTime.Now.ToString() + Environment.NewLine; } cplex.End(); } catch (ILOG.Concert.Exception ex) { textBox1.Text += "Concert Error: " + ex + Environment.NewLine; textBox1.Text += DateTime.Now.ToString() + Environment.NewLine; } }
private void button1_Click(object sender, EventArgs e) { int[,] A = new int[, ] { { 1, 1, 1, 1, 0 }, { 1, 1, 0, 1, 1 }, { 0, 1, 1, 1, 1 } }; double[] L = new double[] { 8, 5, 7, 8, 4 }; double G = 10.7; double[] N_Max = new double[] { 2, 2, 2 }; int nbOfWorkers = A.GetLength(0); int nbOfTasks = A.GetLength(1); Cplex cplex = new Cplex(); INumVar[,] X = new INumVar[nbOfWorkers, nbOfTasks]; // C라는 2차원 인덱스가 0이면, 행의 개수을 받겠다 // C라는 2차원 인덱스가 1이면 열의 개수를 받겠다. for (int i = 0; i < A.GetLength(0); i++) { for (int j = 0; j < A.GetLength(1); j++) { X[i, j] = cplex.BoolVar(); } } List <INumVar> D_negative = new List <INumVar>(); for (int i = 0; i < nbOfWorkers; i++) { D_negative.Add(cplex.NumVar(0, double.MaxValue)); } List <INumVar> D_positive = new List <INumVar>(); for (int i = 0; i < nbOfWorkers; i++) { D_positive.Add(cplex.NumVar(0, double.MaxValue)); } //목적함수 ILinearNumExpr objectiveFunction = cplex.LinearNumExpr(); for (int i = 0; i < nbOfWorkers; i++) { objectiveFunction.AddTerm(1, D_negative[i]); } for (int i = 0; i < nbOfWorkers; i++) { objectiveFunction.AddTerm(1, D_positive[i]); // C[i, j], X[i, j] 두개를 곱해서 objectiveFunction 에 넣겠다. } //과제 for (int i = 0; i < nbOfWorkers; i++) { ILinearNumExpr constLeft1 = cplex.LinearNumExpr(); for (int j = 0; j < nbOfTasks; j++) { constLeft1.AddTerm(L[j], X[i, j]); } constLeft1.AddTerm(1, D_negative[i]); constLeft1.AddTerm(-1, D_positive[i]); cplex.AddEq(constLeft1, G); } for (int j = 0; j < nbOfTasks; j++) { ILinearNumExpr constLeft2 = cplex.LinearNumExpr(); for (int i = 0; i < X.GetLength(0); i++) { constLeft2.AddTerm(1, X[i, j]); } cplex.AddEq(constLeft2, 1); } for (int i = 0; i < nbOfWorkers; i++) { for (int j = 0; j < nbOfTasks; j++) { cplex.AddLe(X[i, j], A[i, j]); } } for (int i = 0; i < nbOfWorkers; i++) { ILinearNumExpr constLeft4 = cplex.LinearNumExpr(); for (int j = 0; j < nbOfTasks; j++) { constLeft4.AddTerm(1, X[i, j]); } cplex.AddLe(constLeft4, N_Max[i]); } cplex.AddMinimize(objectiveFunction); cplex.Solve(); string solution = ""; double tolerance = cplex.GetParam(Cplex.Param.MIP.Tolerances.Integrality); //tolerance를 정의함 for (int i = 0; i < A.GetLength(0); i++) { for (int j = 0; j < A.GetLength(1); j++) { if (cplex.GetValue(X[i, j]) >= 1 - tolerance) { solution += "(" + (i + 1).ToString() + " ," + (j + 1).ToString() + ")"; } } } MessageBox.Show("목적함수 값은 =" + cplex.GetObjValue() + "\r\n" + "선택된 변수는 =" + solution); }