差分约束系统C++实现

差分约束:线性规划矩阵A的每一行包含一个1与一个-1,其他元素为0.因此,由Ax<=b给出的约束条件是m个差分约束集合,其中包含n个未知元。每个约束条件为不等式:

xj-xi<=bk

其中1<=i,j<=n,i<=k<=m

解决方法:把n个未知元看成n的有向图的顶点,xj-xi<=bk表示顶点j到顶点i长度为bk的有向线段。再添加一个v0顶点,与v0到其余顶点的有向线段,长度为0。(如下图)

可以证明 xi=β(v0,vi)(β(v0,vi)为顶点0到顶点i的最短路径长度)。所以就可以利用Bellman_Ford算求单源最短路径(不能用Dijkstra算法,因为有向线段长度可以为负)

// 差分约束系统.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<iostream>
#define MAX 100
#define Infinity 65535
using namespace std;

//边的尾节点结构体
struct edgeNode
{
int no; //边尾端的序号
int weight; //边权值
struct edgeNode * next; //下一个
};

//节点结构体
struct vexNode
{
char info; //节点名称
struct edgeNode *link; //与之相连的端点
};

//存储节点信息
vexNode adjlist[MAX];
//前驱节点
int parent[MAX];
源点到节点j最短路径的花费
int lowcost[MAX];
//差分矩阵
int a[MAX][MAX];
//约束集
int w[MAX];

//根据差分矩阵建立邻接表存储
//adjlist为节点集,parent[j]为从0节点到节点j的最短路径的前驱节点
//lowcost[j]为从0节点到节点j的最短路径的代价
//w为输入的差分约束
//m,n分别为差分矩阵的行数和列数
void createGraph(vexNode *adjlist,int *parent,int *lowcost,int *w,int m,int n)
{
int i,j;
//初始化,节点vi的名称为char(a+i)
for(i=0;i<=n;i++)
{
adjlist[i].info = (char)('a' + i);
adjlist[i].link = NULL;
lowcost[i] = Infinity;
parent[i] = i;
}
int col1,col2;
col1 = col2 = 0;
edgeNode *p1;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(a[i][j]==-1)
col1 = j;
else if(a[i][j]==1)
col2 = j;
}
p1 = (edgeNode*)malloc(sizeof(edgeNode));
p1->no = col2;
p1->weight = w[i];
p1->next = adjlist[col1].link;
adjlist[col1].link = p1;
}
for(i=1;i<=n;i++)
{
p1 = (edgeNode*)malloc(sizeof(edgeNode));
p1->no = i;
p1->weight = 0;
p1->next = adjlist[0].link;
adjlist[0].link = p1;
}
lowcost[0] = 0;
}

//寻找v0到,每一个节点的最短路径
bool Bellman_Ford(vexNode *adjlist,int *lowcost,int *parent,const int n)
{
int i,j;
for(j=0;j<n;j++)
{
for(i=0;i<=n;i++)
{
edgeNode *p1 = adjlist[i].link;
while(p1 != NULL)
{
if(lowcost[i]+p1->weight <lowcost[p1->no])
{
lowcost[p1->no] = lowcost[i]+p1->weight;
parent[p1->no] = i;
}
p1 = p1->next;
}
}
}
//检查有无负回路
for(i=1;i<=n;i++)
{
edgeNode *p2 = adjlist[i].link;
while(p2 != NULL)
{
if(lowcost[p2->no]>lowcost[i]+p2->weight)
return false;
p2 = p2->next;
}
}
return true;
}

int _tmain(int argc, _TCHAR* argv[])
{
int cases;
cout<<"请输入案例的个数:";
cin>>cases;
while(cases--)
{
int i,j;
int n,m;
cout<<"请输入差分矩阵的行数(m)与列数(n):";
cin>>m>>n;
cout<<"请输入差分矩阵:"<<endl;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];
cout<<"请输入约束集:"<<endl;
for(i=1;i<=m;i++)
cin>>w[i];
//创建邻接表
createGraph(adjlist,parent,lowcost,w,m,n);
//输出邻接表
/*
for(i=0;i<=n;i++)
{
edgeNode *p = adjlist[i].link;
cout<<i<<":";
while(p != NULL)
{
cout<<"("<<p->no<<","<<p->weight<<") ";
p = p->next;
}
cout<<endl;
}
*/
//调用Bellman-Ford算法
bool flag = Bellman_Ford(adjlist,lowcost,parent,n);
if(!flag)
cout<<"无解"<<endl;
else
{
//输出解集
cout<<"其中一个解集为(此解集加上一个任意的常数d也是其解集):"<<endl;
for(i=1;i<=n;i++)
cout<<"x"<<i<<"="<<lowcost[i]<<endl;
}
}
system("pause");
return 0;
}

---------------------------------------------------程序测试---------------------------------------------------

请输入案例的个数:1
请输入差分矩阵的行数(m)与列数(n):8 5
请输入差分矩阵:
1 -1 0 0 0
1 0 0 0 -1
0 1 0 0 -1
-1 0 1 0 0
-1 0 0 1 0
0 0 -1 1 0
0 0 -1 0 1
0 0 0 -1 1
请输入约束集:
0 -1 1 5 4 -1 -3 -3
其中一个解集为(此解集加上一个任意的常数d也是其解集):
x1=-5
x2=-3
x3=0
x4=-1
x5=-4
请按任意键继续. . .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
差分进化算法(Differential Evolution,DE)是一种全局优化算法,它通过不断地在种群中进行差分操作来实现优化。差分进化算法具有简单、高效、易于实现等优点,在实际应用中得到了广泛的应用。本文将介绍差分进化算法的原理和C++实现。 1.差分进化算法原理 差分进化算法的基本思想是通过多次迭代,利用种群中的个体之间的差异来寻找全局最优解。算法的过程中,每个个体都被表示为一个向量,其中每个元素表示个体在问题空间中的一个维度。初始时,随机生成一组个体作为初始种群,并根据某种评价函数对每个个体进行评价。评价函数的结果将决定个体的适应度值。 在差分进化算法的迭代过程中,每个个体都会根据其周围的个体进行差分操作,生成一个新的个体。假设当前个体为x,那么它周围的k个个体可以表示为x1, x2, ..., xk。差分操作的过程是将x1, x2, ..., xk中的两个个体相减,然后将差乘以一个系数F,再将结果加上x3,得到一个新的个体y。具体地,差分操作的公式如下所示: y = x1 + F*(x2 - x3) 其中F是一个控制变异程度的参数,通常取值在[0, 2]之间。 生成新个体后,根据评价函数计算该个体的适应度值,并与原个体进行比较。如果新个体的适应度值更好,则将其作为下一代种群中的个体;否则,保留原个体不变。 通过不断地进行差分操作和选择,差分进化算法可以逐步优化种群中的个体,从而达到全局最优解。 2.C++实现 下面是差分进化算法的C++实现代码: #include <iostream> #include <cmath> #include <vector> #include <algorithm> #include <cstdlib> #include <ctime> // 目标函数 double target(double x, double y) { return sin(x) * cos(y); } // 差分进化算法 void differentialEvolution(int popSize, int maxGen, double F, double CR, double lb, double ub) { // 随机数生成器 std::srand(std::time(nullptr)); // 初始化种群 std::vector<std::vector<double>> pop(popSize, std::vector<double>(2)); for (int i = 0; i < popSize; ++i) { pop[i][0] = lb + (ub - lb) * std::rand() / RAND_MAX; // 随机生成x pop[i][1] = lb + (ub - lb) * std::rand() / RAND_MAX; // 随机生成y } // 迭代优化 for (int gen = 0; gen < maxGen; ++gen) { // 遍历每个个体 for (int i = 0; i < popSize; ++i) { // 随机选择三个不同的个体 int j1, j2, j3; do { j1 = std::rand() % popSize; } while (j1 == i); do { j2 = std::rand() % popSize; } while (j2 == i || j2 == j1); do { j3 = std::rand() % popSize; } while (j3 == i || j3 == j1 || j3 == j2); // 变异操作 std::vector<double> v(2); for (int j = 0; j < 2; ++j) { v[j] = pop[j1][j] + F * (pop[j2][j] - pop[j3][j]); v[j] = std::max(lb, std::min(v[j], ub)); // 约束处理 } // 交叉操作 int k = std::rand() % 2; std::vector<double> u(2); for (int j = 0; j < 2; ++j) { if (std::rand() / double(RAND_MAX) < CR || j == k) { u[j] = v[j]; } else { u[j] = pop[i][j]; } } // 选择操作 double f1 = target(pop[i][0], pop[i][1]); double f2 = target(u[0], u[1]); if (f2 > f1) { pop[i] = u; } } } // 输出结果 double bestx = pop[0][0]; double besty = pop[0][1]; double bestf = target(bestx, besty); for (int i = 1; i < popSize; ++i) { double f = target(pop[i][0], pop[i][1]); if (f > bestf) { bestx = pop[i][0]; besty = pop[i][1]; bestf = f; } } std::cout << "best x: " << bestx << std::endl; std::cout << "best y: " << besty << std::endl; std::cout << "best f: " << bestf << std::endl; } int main() { differentialEvolution(100, 1000, 0.8, 0.9, -3.14, 3.14); return 0; } 在上述代码中,differentialEvolution函数表示差分进化算法的实现。其中,popSize表示种群大小,maxGen表示最大迭代次数,F和CR分别表示差分和交叉的控制参数,lb和ub分别表示优化变量的下界和上界。target函数表示要优化的目标函数,本例中为sin(x) * cos(y)。在主函数中,调用differentialEvolution函数进行优化,并输出最优解。 3.总结 本文介绍了差分进化算法的原理和C++实现,并给出了一个简单的例子。差分进化算法是一种简单、高效、易于实现的全局优化算法,在实际应用中具有广泛的应用前景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值