最近碰到了一个有趣的问题,类似于着色问题。
有24个格子可以给我们填色,我们填色的种类有三种,分别为:黄色、蓝色、红色,每种颜色的每次填色时占用的格子数目不一样,分别为,黄色占1格,蓝色占2格,红色占4格。
除此之外,我们还有限制条件是:(1)每种颜色不可以连续着色,如要连续着色,必须在两次着色中间空一格空白格子。(2)每种着色必须至少着色一次,最多着色6次。(3)所有着色所有占据的格子不能超过24这个上限。
我们求解的目标是:着色的总次数最大是多少呢?
我们把问题抽象为一个MIP模型。建立一下模型
我们设置72个变量,就是Xij,当X11为1时表示第一个格子的被第一种资源所占用,但是这样设计有个缺陷,无法通过求解的Xij去准确知到第几个格子如何着色。这部分是以后要改善的问题。
(1.1)代表优化目标,所有的Xij的相加值最大,代表累积的着色次数最大
从(1.2)开始都是限制条件。
(1.2)代表每个格子只能被一种类型着色
(1.3)代表相邻之间着色的类型不可以一样
(1.4)代表所有着色类型所占的格子总数不可以超过24
(1.5)——(1.7)代表每种着色业务数量至少为1,不超过6
(1.8)代表i,j都是整数,且Xij只能取0或1
Java代码如下(比较粗糙,基本功能可以完成):
public optimal() {
try {
GRBEnv grbEnv = new GRBEnv("coloring");
grbModel =new GRBModel(grbEnv);
grbVars = new ArrayList<>();
for (int i = 0; i < 24; i++) {
for (int j = 0; j < 3; j++) {
x[i][j] = grbModel.addVar(0,1,0,GRB.BINARY,"x_"+(i+1)+"_"+(j+1));
grbVars.add(x[i][j]);
x_total[i*3 + j] = x[i][j];
}
}
/*constr1*/
for (int i = 0; i < 24; i++) {
GRBLinExpr expr1 = new GRBLinExpr();
expr1.addTerms(new double[]{1,1,1},x[i]);
grbModel.addConstr(expr1,LESS_EQUAL,1,"expr1"+i);
}
/*constr2*/
for (int i = 0; i < 23; i++) {
for (int j = 0; j < 3 ; j++) {
GRBLinExpr expr2 = new GRBLinExpr();
GRBVar[] grbVars1 = {x[i][j],x[i+1][j]};
expr2.addTerms(new double[]{1,1},grbVars1);
grbModel.addConstr(expr2,LESS_EQUAL,1,"expr2_"+i+j);
}
}
/*constr3*/
GRBLinExpr expr3 = new GRBLinExpr();
double[] expr3_coffe = new double[72];
for (int i = 0; i < 24; i++) {
expr3_coffe[i*3 + 0] = 1;
expr3_coffe[i*3 + 1] = 2;
expr3_coffe[i*3 + 2] = 4;
}
expr3.addTerms(expr3_coffe,x_total);
grbModel.addConstr(expr3,LESS_EQUAL,24,"expr3");
/*constr4*/
double[] expr4_coffe = new double[24];
for (int i = 0; i < 24; i++) {
expr4_coffe[i] = 1;
}
GRBVar[][] grbVars_main = new GRBVar[3][24];
GRBVar[] grbVars1 = new GRBVar[24];
GRBVar[] grbVars2 = new GRBVar[24];
GRBVar[] grbVars4 = new GRBVar[24];
for (int i = 0; i < 24; i++) {
grbVars1[i] = x[i][0];
grbVars2[i] = x[i][1];
grbVars4[i] = x[i][2];
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 24; j++) {
if(i == 0){
grbVars_main[i][j] = grbVars1[j];
} else if (i == 1) {
grbVars_main[i][j] = grbVars2[j];
}else {
grbVars_main[i][j] = grbVars4[j];
}
}
}
for (int i = 0; i < 3; i++) {
GRBLinExpr expr4 = new GRBLinExpr();
expr4.addTerms(expr4_coffe,grbVars_main[i]);
if(i == 0){
grbModel.addConstr(0,LESS_EQUAL,expr4,"expr4_"+i+"_"+1);
grbModel.addConstr(expr4,LESS_EQUAL,5,"expr4_"+i+"_"+2);
}else if(i == 1){
grbModel.addConstr(0,LESS_EQUAL,expr4,"expr4_"+i+"_"+1);
grbModel.addConstr(expr4,LESS_EQUAL,3,"expr4_"+i+"_"+2);
}else {
grbModel.addConstr(0,LESS_EQUAL,expr4,"expr4_"+i+"_"+1);
grbModel.addConstr(expr4,LESS_EQUAL,3,"expr4_"+i+"_"+2);
}
}
/*target*/
double[] target_coffe = new double[72];
for (int i = 0; i < 72; i++) {
target_coffe[i] = 1;
}
GRBLinExpr target = new GRBLinExpr();
target.addTerms(target_coffe,x_total);
grbModel.setObjective(target,GRB.MAXIMIZE);
grbModel.optimize();
int type1_count = 0;
int type2_count = 0;
int type3_count = 0;
int seq_ini[] = new int[72];
int seq_final[] = new int[(int) grbModel.get(GRB.DoubleAttr.ObjVal)];
for (int i = 0; i < x_total.length; i++) {
if(x_total[i].get(GRB.DoubleAttr.X) == 1){
if(i % 3 == 0){
type1_count++;
seq_ini[i] = 1;
} else if (i % 3 == 1) {
type2_count++;
seq_ini[i] = 2;
}else {
type3_count++;
seq_ini[i] = 4;
}
}
}
int temp = 0;
for (int i = 0; i < seq_ini.length; i++) {
if(seq_ini[i] != 0){
seq_final[temp] = seq_ini[i];
temp++;
}
}
//输出结果
System.out.println("最优解为:" + grbModel.get(GRB.DoubleAttr.ObjVal));
System.out.println("Type1的数量为:"+type1_count );
System.out.println("Type2的数量为:"+type2_count );
System.out.println("Type3的数量为:"+type3_count );
System.out.println("业务的顺序为:"+ Arrays.toString(seq_final));
for (int i = 0; i < x_total.length; i++) {
System.out.println(x_total[i].get(GRB.StringAttr.VarName) + "=" +
x_total[i].get(GRB.DoubleAttr.X));
}
//处理模型和环境
grbModel.dispose();
grbEnv.dispose();
}catch (Exception e){
e.printStackTrace();
}
}