2-opt优化——C语言实现

概述

一般情况下,我们找最优路径采取贪心(greedy)策略,都可以收到一个比较好的成效,但是如果我们想要得到一个更优的解,这时候就需要对我们的贪心策略进行优化。但是其实用一个算法找到最优的解是一个非常困难的问题,我们一般会用一个概率上的优化,就是如果重复次数足够多,找不到一个更好的解,我们就认为这个解是最优的。这里就介绍一种2-opt的优化方式。

基本思想

其实2-opt的想法非常简单
(1)我们随机交换路径中的两个点的位置(当然也要保留这两个点之间的路径)
比如说原路径为1 2 3 4 5,交换2, 5,我们得到的新路径为1 5 4 3 2
(2)如果交换后的路径比原来的路径更加优化(一般是对比路径和),我们就保留交换后的路径。
(3)重复(1),(2)直到交换N次仍然无法更新路径停止。

具体实现的时候,首先是得到一条路径,我们可以随机给出一条路径,或者是用贪心先找到一条路径(推荐后者,因为这样更新路径的次数会少一些),然后生成两个随机数表示交换的两点,关于循环的次数N的选取,要自己经过试验选取一个较为合适的数字(较小则无法找到更优的解,较大导致运算时间过长,要自己实验得出最优化的选择)

操作步骤

(1)使用贪心算法找到一条路径记录在数组A中,并记录下总路径长l1。
(2)随机生成两个不同的随机数n1,n2(将其对应到路径中顶点的下标),交换路径中n1,n2之间的路径,得到一条新路径并记录下路径总长l2。
(3)比较新得到的路径总长与原来的路径总长,若新路径更短,则更新路径为新路径并将计数器cnt_opt置0。否则计数器加1.
(4)重复(2),(3),直到计数器cnt_opt达到MaxCount,MaxCount即为上面提到的合理选择的循环次数N。

代码实现

int main() {
	game_state_t state;
	memset(&state, 0, sizeof(state));
	init(&state);
	// write your code here
	int i, j;
	int cnt_opt = 0;
	double minpath = 0;
	double minpath1 = 0;
	n = state.n;
	m = state.m;
	op.x = state.start_x, op.y = state.start_y;
	AdjGraph G;
	Init(state, &G);
	Floyd(G);
	int num_in = (state.start_x * m + state.start_y);
	for (i = 0; i < n; i++) {
		for (j = 0; j < m; j++) {
			if (state.food[i][j] == 1) {
				n_food[count] = i * m + j;
				count++;
			}
		}
	}
	count1 = count;          
	while (count > 0) {      //这个while循环是用贪心找到一条路径
		int nearest;
		double MIN = 9999.9;
		for (i = 0; i < m * n; i++) {
			int u = i / m;
			int v = i % m;
			if (state.food[u][v] == 1 && A[num_in][i] < MIN && num_in != i) {
				MIN = A[num_in][i];
				nearest = i;
			}
		}
		minpath += MIN;
		int num_out = nearest;
		num_in = num_out;
		state.food[num_out / m][num_out % m] = 0;
		pathway[count1 - count] = num_out;
		count--;
	}
	num_in = (state.start_x * m + state.start_y);
	srand((unsigned)time(NULL));          //随机数种子
	while (cnt_opt <= MaxCount) {          //2-opt算法的循环
		int n1, n2;
		n1 = rand() % count1;
		do {
			n2 = rand() % count1;    

		} while (n1 == n2);
		if (n1 > n2) {
			swap(&n1, &n2);
		}
		int left = n1, right = n2;
		while (left < right) {           //交换两个随机数之间的路径得到新路径
			swap(&pathway[left], &pathway[right]);
			left++; right--;
		}
		minpath1 = 0;
		for (i = 0; i < count1 - 1; i++) {
			minpath1 += A[pathway[i]][pathway[i + 1]];
		}
		minpath1 += A[num_in][pathway[0]];
		if (minpath1 < minpath) {
			minpath = minpath1;
			cnt_opt = 0;
		}
		else {
			left = n1, right = n2;
			while (left < right) {
				swap(&pathway[left], &pathway[right]);
				left++; right--;
			}
			cnt_opt++;
		}
	}
	for (i = 0; i < count1; i++) {
		int num_out = pathway[i];
		BFS(G, num_in, num_out);
		transfor(num_out, &state);
		j = 0;
		while (path_BFS[j] != num_out) {
			printf("%c", p[j]);
			j++;
		}
		num_in = num_out;
	}
	destroy(&state);
	system("PAUSE");
	return 0;
}

这个代码实现的问题是一个简单的吃豆人寻找最优吃豆路径的算法,地图数据存储在util.h头文件里面,还有较多的数据结构为给出有需要的自取源码
https://github.com/yiguang-hack/2-opt/tree/master

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值