c++ SCIP求解整数规划模型

SCIP是一款开源的求解整数规划求解器,跟cplex、gurobi一样。

到SCIP官网下载软件 https://scipopt.org/#download ,下载10.0.1版本的.exe程序,点击安装。我的路径G:\software\SCIPOptSuite1001,而且G:\software\SCIPOptSuite1001\bin要添加到系统环境变量中。

CMakeLists.txt内容如下:

cpp 复制代码
cmake_minimum_required(VERSION 3.25)
project(P_median_problem)

set(CMAKE_CXX_STANDARD 20)

# 设置 SCIP 根目录(根据你的实际路径修改)
set(SCIP_DIR "G:/software/SCIPOptSuite1001")

# 包含头文件目录
include_directories(${SCIP_DIR}/include)

# 添加库目录(以便 find_library 或直接链接)
link_directories(${SCIP_DIR}/lib)

# 添加可执行文件
add_executable(my_scip_app ../improved_Lagrangian_relaxation/main1_SCIP_MIP.cpp)

# 查找 SCIP 核心库和 SoPlex 库
find_library(SCIP_CORE_LIBRARY NAMES libscip PATHS ${SCIP_DIR}/lib NO_DEFAULT_PATH)
find_library(SOPLEX_LIBRARY NAMES libsoplex libsoplexshared PATHS ${SCIP_DIR}/lib NO_DEFAULT_PATH)

if(NOT SCIP_CORE_LIBRARY)
    message(FATAL_ERROR "SCIP core library not found")
endif()
if(NOT SOPLEX_LIBRARY)
    message(FATAL_ERROR "SoPlex library not found")
endif()

target_link_libraries(my_scip_app ${SCIP_CORE_LIBRARY} ${SOPLEX_LIBRARY} ws2_32 winmm)

# 复制 SCIP bin 目录下所有 DLL 到输出目录
add_custom_command(TARGET my_scip_app POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${SCIP_DIR}/bin"
        $<TARGET_FILE_DIR:my_scip_app>
        COMMENT "Copying SCIP DLLs to output directory"
)

main1_SCIP_MIP.cpp内容如下:

cpp 复制代码
#include <iostream>
#include "scip/scip.h"
#include "scip/scipdefplugins.h"

using namespace std;

int main() {
    // 1. 创建 SCIP 实例并加载默认插件
    SCIP* scip = nullptr;
    SCIP_CALL( SCIPcreate(&scip) );
    SCIP_CALL( SCIPincludeDefaultPlugins(scip) );

    // 2. 创建问题
    SCIP_CALL( SCIPcreateProbBasic(scip, "simple_integer_program") );
    SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE);

    // 3. 创建变量
    SCIP_VAR* x1 = nullptr;
    SCIP_VAR* x2 = nullptr;

    SCIP_CALL( SCIPcreateVar(scip, &x1, "x1", 0.0, SCIPinfinity(scip), 3.0,
                              SCIP_VARTYPE_INTEGER, true, false,
                              nullptr, nullptr, nullptr, nullptr, nullptr) );
    SCIP_CALL( SCIPcreateVar(scip, &x2, "x2", 0.0, SCIPinfinity(scip), 5.0,
                              SCIP_VARTYPE_INTEGER, true, false,
                              nullptr, nullptr, nullptr, nullptr, nullptr) );

    SCIP_CALL( SCIPaddVar(scip, x1) );
    SCIP_CALL( SCIPaddVar(scip, x2) );

    // 4. 创建约束(使用简化版本 SCIPcreateConsBasicLinear)
    SCIP_CONS* cons1 = nullptr;
    SCIP_CONS* cons2 = nullptr;

    // 约束 1: 2x1 + 4x2 <= 100
    {
        SCIP_VAR* vars[2] = { x1, x2 };
        double coeffs[2] = { 2.0, 4.0 };
        SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons1, "resource1",
                                              2, vars, coeffs,
                                              -SCIPinfinity(scip), 100.0) );
        SCIP_CALL( SCIPaddCons(scip, cons1) );
    }

    // 约束 2: 3x1 + 2x2 <= 90
    {
        SCIP_VAR* vars[2] = { x1, x2 };
        double coeffs[2] = { 3.0, 2.0 };
        SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons2, "resource2",
                                              2, vars, coeffs,
                                              -SCIPinfinity(scip), 90.0) );
        SCIP_CALL( SCIPaddCons(scip, cons2) );
    }

    // 释放约束(已添加到问题,可以释放)
    SCIP_CALL( SCIPreleaseCons(scip, &cons1) );
    SCIP_CALL( SCIPreleaseCons(scip, &cons2) );

    // 5. 设置求解器参数
    SCIP_CALL( SCIPsetRealParam(scip, "limits/time", 60.0) );   // 限制求解时间 60 秒
    SCIP_CALL( SCIPsetIntParam(scip, "display/verblevel", 5) ); // 输出详细日志

    // 6. 求解
    cout << "Starting optimization..." << endl;
    SCIP_CALL( SCIPsolve(scip) );

    // 7. 获取解
    SCIP_SOL* sol = SCIPgetBestSol(scip);
    if ( sol ) {
        double objval = SCIPgetSolOrigObj(scip, sol);
        double x1_val = SCIPgetSolVal(scip, sol, x1);
        double x2_val = SCIPgetSolVal(scip, sol, x2);

        cout << "\nOptimal solution found!" << endl;
        cout << "Objective value = " << objval << endl;
        cout << "x1 = " << x1_val << endl;
        cout << "x2 = " << x2_val << endl;
    } else {
        cout << "No solution found." << endl;
    }

    // 8. 清理
    SCIP_CALL( SCIPreleaseVar(scip, &x1) );
    SCIP_CALL( SCIPreleaseVar(scip, &x2) );
    SCIP_CALL( SCIPfree(&scip) );

    return 0;
}

运行结果如下:

cpp 复制代码
Starting optimization...
LP Solver <SoPlex 8.0.1>: barrier convergence tolerance cannot be set -- tolerance of SCIP and LP solver may differ
LP Solver <SoPlex 8.0.1>: fastmip setting not available -- SCIP parameter has no effect
LP Solver <SoPlex 8.0.1>: number of threads settings not available -- SCIP parameter has no effect
transformed problem has 2 variables (0 bin, 2 int, 0 cont) and 2 constraints
      2 constraints of type <linear>

original problem has 4 active (100%) nonzeros and 4 (100%) check nonzeros

feasible solution found by trivial heuristic after 0.0 seconds, objective value 0.000000e+00
presolving:
(round 1, fast)       0 del vars, 0 del conss, 0 add conss, 3 chg bounds, 0 chg sides, 0 chg coeffs, 0 upgd conss, 0 impls, 0 clqs, 0 implints
   (0.0s) running MILP presolver
   (0.0s) MILP presolver found nothing
(round 2, exhaustive) 0 del vars, 0 del conss, 0 add conss, 3 chg bounds, 0 chg sides, 0 chg coeffs, 2 upgd conss, 0 impls, 0 clqs, 0 implints
   (0.0s) symmetry computation started: requiring (bin +, int +, cont +), (fixed: bin -, int -, cont -)
   (0.0s) no symmetry present (symcode time: 0.00)
clique table cleanup detected 0 bound changes

presolved problem has 4 active (100%) nonzeros and 4 (100%) check nonzeros

presolving (3 rounds: 3 fast, 2 medium, 2 exhaustive):
 0 deleted vars, 0 deleted constraints, 0 added constraints, 3 tightened bounds, 0 added holes, 0 changed sides, 0 changed coefficients
 0 implications, 0 cliques, 0 implied integral variables (0 bin, 0 int, 0 cont)
presolved problem has 2 variables (0 bin, 2 int, 0 cont) and 2 constraints
      2 constraints of type <varbound>
transformed objective value is always integral (scale: 1)
Presolving Time: 0.00
transformed 1/1 original solutions to the transformed problem space

 time | node  | left  |LP iter|LP it/n|mem/heur|mdpt |vars |cons |rows |cuts |sepa|confs|strbr|  dualbound   | primalbound  |  gap   | compl. 
p 0.0s|     1 |     0 |     0 |     - | vbounds|   0 |   2 |   2 |   2 |   0 |  0 |   0 |   0 | 2.150000e+02 | 9.000000e+01 | 138.89%| unknown
p 0.0s|     1 |     0 |     0 |     - | vbounds|   0 |   2 |   2 |   2 |   0 |  0 |   1 |   0 | 2.150000e+02 | 1.250000e+02 |  72.00%| unknown
* 0.0s|     1 |     0 |     2 |     - |    LP  |   0 |   2 |   2 |   2 |   0 |  0 |   3 |   0 | 1.350000e+02 | 1.350000e+02 |   0.00%| unknown
  0.0s|     1 |     0 |     2 |     - |   843k |   0 |   2 |   2 |   2 |   0 |  0 |   3 |   0 | 1.350000e+02 | 1.350000e+02 |   0.00%| unknown

SCIP Status        : problem is solved [optimal solution found]
Solving Time (sec) : 0.00
Solving Nodes      : 1
Primal Bound       : +1.35000000000000e+02 (4 solutions)
Dual Bound         : +1.35000000000000e+02
Gap                : 0.00 %

Optimal solution found!
Objective value = 135
x1 = 20
x2 = 15

Process finished with exit code 0
相关推荐
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
郝学胜_神的一滴3 天前
CMake 034:生成器表达式:解耦构建时序、精简分支逻辑的终极利器
c++·cmake
见过夏天3 天前
C++ 基础入门完全指南
c++
用户805533698035 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK5 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
卷无止境6 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境6 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴7 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
卷无止境9 天前
C++ 的Eigen 库全解析
c++
卷无止境9 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端