旅行商售货问题

#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 100;
const int NoEdge = 0x3f3f3f3f;	//用最大值代表两城市间无边 

int n;					//城市个数 
int m;					//邻接矩阵graph边数 
int x[maxn];			//当前解,表示从解空间树根到当前结点代表的所经过的城市 
int bestx[maxn];		//当前最优解,已搜索的部分解空间树中费用最小周游路线所对应的经过的城市 
int graph[maxn][maxn];	//城市之间的临界矩阵,当graph[i][j] = NoEdge时,表示城市i和j无边 
int cc;					//当前费用 
int bestc = NoEdge;		//最小费用 

//交换 
void Swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}

void Backtrack(int i)
{
	if(i == n)//当i=n时,当前扩展结点是排列树的叶结点的父结点
	{
		//算法是否存在从城市x[n-1]到城市x[n]的边和从城市x[n]到城市x[1]的边
		if(graph[x[n - 1]][x[n]] != NoEdge && graph[x[n]][1] != NoEdge
		//判断这条回路的费用是否优于已找到的当前最优回路费用
		&& (cc + graph[x[n - 1]][x[n]] + graph[x[n]][1] < bestc || bestc == NoEdge))
		{
			//更新当前当前最优解bestx
			for(int j = 1; j <= n; j++)
				bestx[j] = x[j];
			//更新当前最优值bestc
			bestc = cc + graph[x[n - 1]][x[n]] + graph[x[n]][1];
		}
		return;
	}
	else
	{
		for(int j = i; j <= n; j++)
		{
			//是否可进入x[j]子树?
			if(graph[x[i - 1]][x[j]] != NoEdge && //检测是否存在一条从城市x[i-1]到城市x[j]的边
			(cc + graph[x[i - 1]][x[j]] < bestc || bestc == NoEdge)
			/*判断从根结点到当前搜索结点处的部分周游
			路线的费用是否小于当前找到的最小费用周游路线*/ 
			)
			//如果满足约束函数和限界函数,则搜索以当前搜索结点为根的子树
			Swap(&x[i], &x[j]);
			cc += graph[x[i - 1]][x[i]];
			Backtrack(i + 1);
			//回溯还原 
			cc -= graph[x[i - 1]][x[i]];
			Swap(&x[i], &x[j]);
		}
	}	
}

int main()
{
	fill(graph[0], graph[0] + maxn * maxn, NoEdge);//初始化邻接矩阵为NoEdge 
	cin >> n >> m;
	while(m--)
	{
		int a, b, c;
		cin >> a >> b >> c;
		graph[a][b] = graph[b][a] = c;
	}
	//注意:调用函数回溯搜索前要将数组x初始化为(1,2,…,n)
	for(int i = 1; i <= n; i++)	
		x[i] = i;
	Backtrack(2);
	cout << "最小花费为:" << bestc << endl; 
	cout << "路径为:" << endl;
	for(int i = 1; i <= n; i++)
		cout << bestx[i] << " ";
	cout << bestx[1] << endl;
}

/*
测试: 
4 6
1 2 30
1 3 6
1 4 4
2 4 10
2 3 5
3 4 20
*/

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值