You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java CPLEX求解p-median问题?请分析该实现方案可行性

P-Median问题的Java实现可行性分析

以下是与CPLEX Studio/opl/examples/opl/pmedian中自带示例等价的OPL模型的Java实现:

import ilog.concert.IloConstraint;
import ilog.concert.IloException;
import ilog.concert.IloLinearNumExpr;
import ilog.concert.IloNumVar;
import ilog.concert.IloRange;
import ilog.cplex.IloCplex;


public class P_Median {

    public static void main(String args[]) {
        solveMe();
    }

    public static void solveMe() {

        int p = 2;

        int n = 4;   // customers
        int m = 3;   // warehouses

        String[] customers = { "Albert", "Bob", "Chris", "Daniel" };
        String[] warehouses = { "Santa Clara", "San Jose", "Berkeley" };
        double[] demand = { 100.0, 80.0, 80.0, 70.0 };
        double[][] distance = { {  2.0, 10.0, 50.0 },
                                {  2.0, 10.0, 52.0 }, 
                                { 50.0, 60.0,  3.0 },
                                { 40.0, 60.0,  1.0 } };

        double[][]cost = new double [n][m];
        for (int c = 0; c < n; c++) {
            for (int w = 0; w < m; w++) {
                cost[c][w] = demand[c]*distance[c][w];
            }
        }
        System.out.println("cost   = [");
        for (int c = 0; c < n; c++) {
            for (int w = 0; w < m; w++) {
                System.out.print(cost[c][w] + "\t");
            }
            System.out.print("\n\r");
        }
        System.out.println("]");

        IloCplex cplex = null;

        try {
            // define new model
            cplex  = new IloCplex();
            //cplex.setParam(IloCplex.Param.Simplex.Display, 0);

            //variables
            IloNumVar[] openWarehouse = new IloNumVar[m];
            for (int w = 0 ; w < m; w++) {
                openWarehouse[w] = cplex.boolVar("openWarehouse"+"_"+w);
            }

            IloNumVar[][] shipToCustomer = new IloNumVar[n][m];
            for (int c = 0; c < n; c++) {
                for (int w = 0; w < m; w++) {
                    shipToCustomer[c][w] = cplex.boolVar("shipToCustomer"+"_"+c+"_"+w);
                }
            }

            //objective
            IloLinearNumExpr objective = cplex.linearNumExpr();
            for (int c = 0; c < n; c++) {
                for (int w = 0; w < m; w++) {
                    objective.addTerm(cost[c][w],shipToCustomer[c][w]);
                }
            }
            cplex.addMinimize(objective);

            // constraints
            IloConstraint[] shipConstraints = new IloConstraint[n];
            IloLinearNumExpr[] shipConstraintExpression = new IloLinearNumExpr[n];
            for (int c=0; c<n; c++) {
                shipConstraintExpression[c] = cplex.linearNumExpr();
                for (int w=0; w<m; w++) {
                    shipConstraintExpression[c].addTerm(1.0, shipToCustomer[c][w]);
                }
                IloRange shipConstraint = cplex.addEq(shipConstraintExpression[c], 1);
                shipConstraint.setName("shipConstraint"+c);
                shipConstraints[c]=shipConstraint;
            }

            IloLinearNumExpr openConstraintExpression = cplex.linearNumExpr();
            for (int w=0; w<m; w++) {
                openConstraintExpression.addTerm(1.0, openWarehouse[w]);
            }
            IloRange openConstraint = cplex.addEq(openConstraintExpression, p);
            openConstraint.setName("openConstraint");

            IloConstraint[][] shipOpenConstraints = new IloConstraint[n][m];
            IloLinearNumExpr[][] shipOpenExpression = new IloLinearNumExpr[n][m];
            for (int c = 0; c < n; c++) {
                for (int w = 0; w < m; w++) {
                    shipOpenExpression[c][w] = cplex.linearNumExpr();
                    shipOpenExpression[c][w].addTerm(1.0, shipToCustomer[c][w]);
                    IloConstraint shipOpenConstraint = cplex.addLe(shipOpenExpression[c][w], openWarehouse[w]);
                    shipOpenConstraint.setName("shipOpenConstraint"+c+w);
                    shipOpenConstraints[c][w]=shipOpenConstraint;
                }
            }

            // solve model
            if (cplex.solve()) {

                System.out.println("\nSolution status = "+ cplex.getStatus()+"\n");
                System.out.println("obj = "+cplex.getObjValue());

                System.out.println("openWarehouse   = [");
                for (int w = 0 ; w < m; w++) {
                    System.out.print(cplex.getValue(openWarehouse[w]) + "\t");
                }
                System.out.println("]");


                System.out.println("shipToCustomer   = [");
                for (int c = 0; c < n; c++) {
                    for (int w = 0; w < m; w++) {
                        System.out.print(cplex.getValue(shipToCustomer[c][w]) + "\t");
                    }
                    System.out.print("\n\r");
                }
                System.out.println("]");

                System.out.println("------ ship Constraints -----");
                for (int c=0;c<shipConstraints.length;c++) {
                    System.out.print(((IloRange) shipConstraints[c])+" -> "+"\t");
                    System.out.print("slack constraint "+(c+1)+" = "+cplex.getSlack((IloRange) shipConstraints[c])+"\n");
                }

                System.out.println("------ open Constraint -----");
                System.out.print(((IloRange) openConstraint)+" -> "+"\t");
                System.out.print("slack constraint  = "+cplex.getSlack((IloRange) openConstraint)+"\n");

                System.out.println("------ ship Open Constraints -----");
                for (int c = 0; c < n; c++) {
                    for (int w = 0; w < m; w++) {
                        System.out.print(((IloRange) shipOpenConstraints[c][w])+" -> "+"\t");
                        System.out.print("slack constraint "+(c+1)+""+(w+1)+" = "+cplex.getSlack((IloRange) shipOpenConstraints[c][w])+"\n");
                    }
                }


            } else {
                System.out.println("problem not solved");
            }

        } catch (IloException exc) {
            exc.printStackTrace();
        } finally {
            if(cplex!=null) cplex.end();
        }

    }

}

问题:请分析该解决方案是否可行?

整数规划相关背景

整数规划是一类数学优化或可行性规划问题,其中部分或全部变量被限制为整数。多数场景下,该术语特指整数线性规划(ILP)——目标函数和除整数约束外的其他约束均为线性的规划问题。

整数规划属于NP完全问题,尤其是0-1整数线性规划这一特例:其中变量为二进制且只需满足约束条件,它是卡普提出的21个NP完全问题之一。若部分决策变量为非离散型,则这类问题被称为混合整数规划问题。


可行性分析结论

该Java解决方案完全可行,具体依据如下:

  1. 模型逻辑准确性
    • 完整复现了P-Median问题的核心需求:
      • 用二进制变量openWarehouse标记仓库是否启用,shipToCustomer标记是否从某仓库向某客户供货
      • 目标函数正确定义为最小化总运输成本(需求与距离的乘积之和)
      • 约束条件覆盖了P-Median问题的核心规则:
        • 每个客户必须被恰好一个仓库覆盖(shipConstraints约束)
        • 恰好启用指定数量的仓库(openConstraint约束)
        • 仅能从已启用的仓库向客户供货(shipOpenConstraints约束)
  2. CPLEX API使用合规性
    • 正确初始化IloCplex求解器实例,并在finally块中调用end()释放资源,避免内存泄漏
    • 变量定义、目标函数构建、约束添加的流程完全符合CPLEX Java API的标准用法
    • 异常处理逻辑覆盖了IloException,可捕获求解过程中的异常并输出详细信息
  3. 问题适配性
    • 针对P-Median这类0-1整数线性规划问题,使用boolVar()定义二进制变量,完全匹配问题类型,CPLEX的整数规划求解器可高效处理该规模的实例

可优化方向

虽然实现可行,但可以做以下小改进提升代码质量:

  • 将硬编码的参数(如p、客户/仓库数量、需求、距离矩阵等)提取为配置项或通过外部文件读取,增强代码灵活性
  • 用日志框架替代System.out打印,便于生产环境的调试与监控
  • 针对大规模P-Median问题,可开启CPLEX的并行求解参数或调整分支定界策略,提升求解效率

内容的提问来源于stack exchange,提问作者filipemb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 06:24:54