这篇文章主要参考cplex用户手册
以求解无权无向图的最小顶点覆盖为例,,用C++语言来演示在ubuntu环境下使用cplex求解最小顶点覆盖的全解
- 问题描述
M i n ∑ i = 1 n a i Min\sum_{i=1}^{n}a_i Min∑i=1nai
1 ⩽ a i + a j ⩽ 2 1\leqslant a_{i}+a_{j}\leqslant2 1⩽ai+aj⩽2, ( i , j ) (i,j) (i,j)图 G G G的任意一条边
0 ⩽ a i ⩽ 1 , ( i = 1 , 2 , . . . n ) 0\leqslant a_{i}\leqslant1,(i=1,2,...n) 0⩽ai⩽1,(i=1,2,...n), a i a_{i} ai是整数 - 代码实现
#include <bits/stdc++.h>
#include "ilcplex/ilocplex.h"
using namespace std;
int SIZE, EdgeNum, EdgeSIZE;
struct Vertex
{
int state;
};
Vertex *vertices;
struct Edge
{
int head, tail;
};
Edge *edges;
void readGraph(char *filename)
{
freopen(filename, "r", stdin);
scanf("%d %d", &SIZE, &EdgeNum);
EdgeSIZE = EdgeNum;
vertices = (Vertex *)malloc(SIZE * sizeof(Vertex));
edges = (Edge *)malloc(EdgeNum * sizeof(Vertex));
for(int i = 0; i < EdgeNum; i ++)
{
int head, tail;
scanf("%d %d", &head, &tail);
head --;
tail --;
edges[i].head = head;
edges[i].tail = tail;
}
}
void VertexCoverLP()
{
IloEnv env;//定义环境
IloModel model(env);//定义模型
IloIntVar Ud(env, 0, SIZE);//定义Ud的范围,我这里整形运算
IloIntVarArray a(env, SIZE, 0, 1);//定义变量a[1..n],范围[0,1]为整数
IloRangeArray constraints(env, EdgeNum, 1, 2);//添加边约束,范围为[1,2]
model.add(constraints);//添加约束
IloExpr expr=Ud;//IloExpr 一定要初始化
for (int i = 0; i < SIZE; i++)
{
expr += a[i];
}
model.add(IloMinimize(env, expr));//添加最小约束
for (int i = 0; i < EdgeSIZE; i++) //添加边约束
{
IloExpr expr = a[edges[i].head] + a[edges[i].tail];
constraints[i].setExpr(expr);
}
IloCplex Solver(model);//定义解题器
Solver.setOut(env.getNullStream());//不输出求解日志
Solver.setParam(Solver.SolnPoolAGap, 0.0); //设置解法池的绝对间隙
Solver.setParam(Solver.SolnPoolIntensity, 4); //设置解法池强度参
Solver.setParam(Solver.PopulateLim, 2100000000);//设置按填充针对解法池生成的解法的最大数量
Solver.populate();//调用填充
//输出所有解的信息
for(int i = 0; i < Solver.getSolnPoolNsolns(); i ++)
{
printf("----------------\n");
printf("sol = %d\n", i + 1);
Solver.writeSolution("out.sol", i);
for(int j = 0; j < SIZE; j ++)
{
if(Solver.getValue(a[j], i) == 1) //获取第i个解中变量j的值
{
cout << j + 1 << " ";
}
}
cout << endl;
}
env.end();
}
int main(int argc, char *argv[])
{
char *filename;
filename = argv[1];
cout << filename << endl;
readGraph(filename);
VertexCoverLP();
return 0;
}
- 输出结果
//输入数据
3 3
1 2
2 3
3 1
- 注意
即使对于规模较小的图,其全解的个数个能很大,对全解的求解对于时间和空间的消耗是很大。