TSP问题建模:
测试数据类型:
程序:
// Cplex_template.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <ilcplex/ilocplex.h>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
//获取输入数据,tsp的节点以及节点之间的距离矩阵
std::vector<std::vector<int>> FileRead(std::string filepath) {
std::ifstream file(filepath);
std::vector<std::vector<int>> point;
std::vector<std::vector<int>> distanceMatrix;
if (!file.is_open()) {
std::cerr << "Error: Failed to open file " << filepath << std::endl;
return distanceMatrix;
}
std::string line;
bool readingCoordinates = false;
while (std::getline(file, line)) {
if (line == "NODE_COORD_SECTION") {
readingCoordinates = true;
continue;
}
if (readingCoordinates) {
std::istringstream iss(line);
int nodeIndex;
int x, y;
if (!(iss >> nodeIndex >> x >> y)) {
break;
}
point.push_back({ x,y });
}
}
int nbCity = point.size();
distanceMatrix = std::vector<std::vector<int>>(nbCity, std::vector<int>(nbCity, 0));
for (int i = 0; i < nbCity; i++) {
for (int j = 0; j < nbCity; j++) {
if (i == j) {
distanceMatrix[i][j] = 0;
}
else {
int dx = point[i][0] - point[j][0];
int dy = point[i][1] - point[j][1];
int dis = static_cast<int>(std::sqrt(dx * dx + dy * dy));
distanceMatrix[i][j] = dis;
}
}
}
file.close();
cout << "read successful!";
return distanceMatrix;
}
//获取变量名函数,一个是xij,一个是ui
std::string getVarName(int i, int j) {
std::stringstream ss;
ss << "x_" << i <<"_" << j;
std::string varName = ss.str();
return varName;
}
std::string getVarName(int i) {
std::stringstream ss;
ss << "u_" << i;
std::string varName = ss.str();
return varName;
}
int main() {
//创建变量池,方便后续通过变量名获取模型中的变量,
//由于不能直接由getVarByName, 所以需要一个变量池存加入模型的变量
std::map < string , IloNumVar > NumVarMap ;
std::map < string, IloBoolVar > BoolVarMap;
std::map < string, IloIntVar > IntVarMap;
//获取节点距离矩阵
std::vector<std::vector<int>> distanceMatrix = FileRead("xqf131.tsp");
//获取节点数目
IloInt numCity = distanceMatrix.size();
//创建环境
IloEnv env;
try {
//创建模型
IloModel model(env);
//创建cplex对象
IloCplex cplex(model);
// 向模型中增加决策变量 xij
for (int i = 0; i < numCity; i++) {
for (int j = 0; j < numCity; j++) {
if (i == j) continue;
std::string varName = getVarName(i, j);
IloBoolVar var(env,varName.c_str());
model.add(var);
BoolVarMap.emplace(varName.c_str(),var);
}
}
//向模型中增加决策变量 ui , 每个节点对应一个 ui
for (int i = 0; i < numCity; i++) {
std::string varName = getVarName( i );
IloNumVar var(env, 0.0, IloInfinity, varName.c_str());
model.add(var);
NumVarMap.emplace(varName.c_str(), var);
}
//向obj中做累加。获得目标函数表达式
IloExpr obj(env);
for (int i = 0; i < numCity; i++) {
for (int j = 0; j < numCity; j++) {
if (i == j) continue;
std::string varName = getVarName(i, j);
obj += BoolVarMap[varName] * distanceMatrix[i][j];
}
}
//设置目标函数为最小化形式
model.add(IloMinimize(env, obj));
//向模型中增加约束条件 (1)
for (int i = 0; i < numCity; i++) {
IloExpr cons_1(env);
for (int j = 0; j < numCity; j++) {
if (i == j) continue;
std::string varName = getVarName(i, j);
cons_1 += BoolVarMap[varName];
}
model.add(cons_1 == 1);
}
//向模型中增加约束条件 (2)
for (int j = 0; j < numCity; j++) {
IloExpr cons_2(env);
for (int i = 0; i < numCity; i++) {
if (i == j) continue;
std::string varName = getVarName(i, j);
cons_2 += BoolVarMap[varName];
}
model.add(cons_2 == 1);
}
//向模型中增加约束(3)
for (int i = 1; i < numCity; i++) {
for (int j = 1; j < numCity; j++) {
if (i == j) continue;
IloNumVar ui = NumVarMap[getVarName(i)];
IloNumVar uj = NumVarMap[getVarName(j)];
IloBoolVar xij = BoolVarMap[getVarName( i, j)];
model.add(ui - uj + numCity * xij <= numCity - 1);
}
}
// 设置求解时间
cplex.setParam(IloCplex:: TiLim, 60);
// 求解模型
if (cplex.solve()) {
cout << "Feasible!" << endl;
//输出结果
std::map <int, int> res;
for (int i = 0; i < numCity; i++) {
std::string u_i = getVarName(i);
IloNumVar ui = NumVarMap[u_i];
res.emplace(cplex.getValue(ui),i);
}
for (auto it = res.begin(); it != res.end(); ++it) {
if (it != res.begin()) cout << " ->";
std::cout << it->second + 1;
}
cout << endl;
// 获取目标函数值
cout << "ObjValue: " << cplex.getObjValue();
}
else {
cout << "Infeasible!" << endl;
}
}
catch (IloException& e) {
std::cerr << "Concert exception caught: " << e << std::endl;
}
catch (...) {
std::cerr << "Unknown exception caught" << std::endl;
}
env.end();
return 0;
}
运行结果 :