本人的算法大作业
参考博客:
http://blog.csdn.net/qq_32400847/article/details/51813606
http://www.cnblogs.com/cielosun/p/5654582.html
http://www.cnblogs.com/cielosun/p/5654582.html
基本思想
1.按宽度优先策略遍历解空间树
2.在遍历过程中,对处理的每个结点vi,根据界限函数,估计沿该结点向下搜索所可能达到的完全解的目标函数的可能取值范围—界限bound(vi)=[downi, upi]
3.从中选择使目标函数取的极值(最大、最小)的结点优先进行宽度优先搜索,从而不断调整搜索方向,尽快找到问题解。
各结点的界限函数bound(vi)=[downi, upi]是解决问题的关键,通常依据具体问题而定。常见的两种分支限界法是队列式分支限界法和优先队列式分支限界法,它们分别按照队列先进先出的原则和优先队列中规定的优先级选取下一个节点为扩展节点。分支限界法与回溯法的不同之处在于求解目标和搜索方式的不同。回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解;回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。我们以TSP问题为例用分支限界法解决。TSP问题(Traveling Salesman Problem)是数学领域中著名问题之一。假设有一个旅行商人要拜访N个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市,要求路径的总和最小。考虑下图所示的情况及其代价矩阵,假定起始城市为1号城市。
算法描述
输入:城市数量n和城市之间路程的代价矩阵
输出:城市之间固定起点的哈密顿回路的最短路程
1)计算初始上下界,使用暴力排序对代价矩阵进行排序计算出下界,使用贪心算法计算出上界。
2)定义一个类保存开始节点、结束节点、已遍历的城市及其数量、已遍历的路径长度、当前节点的目标函数值,类中定义一个方法计算当前节点的目标函数值,由当前已遍历的路径的二倍加上进出其余未遍历城市的最短路径,再加上出当前城市的最短路径和进起始城市的最短路径,取其二分之一,是当前节点的目标函数值,即当前节点的下界。
3)把起始节点加入优先队列,当优先队列不为空时,取出当前优先级最高的节点,若当前已遍历n-1个城市,则计算当前路径长度加上最后一个节点的路径长度和记为ans,若ans小于所有目标函数值,则跳出循环并把ans作为最优解输出。若ans不小于所有目标函数值,则更新上界和可行解继续循环。若当前已遍历城市个数小于n-1,则判断当前取出节点的子节点的目标函数是否小于上界,若小于则添加进优先队列,否则继续判断下一个子节点。
样例矩阵
搜索树
结果:
代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<queue>
#define INF 100000
#define MAX 100
using namespace std;
int result;
int weight[MAX][MAX];
class City{
public:
City(){
}
int m_iUpWeight; //上界
int m_iDownWeight; //下界
int m_iCount; //输入的总的城市数量
int visitedCitys[MAX]; //已走过的城市
};
City city;
class Nodes{
public:
int visitedCity[MAX]; //已走过的城市
int numbers; //已走过的城市数量
int endCity; //已走过的最后一个城市
int startCity; //已走过的第一个城市
int sumLength; //已走过的长度
int aimFun; //当前节点的目标函数值
Nodes(){
for(int i=0;i<MAX;++i){
visitedCity[i]=0;
}
visitedCity[0]=1;
numbers=1;
endCity=0;
startCity=0;
sumLength=0;
aimFun=0;
}
bool operator <(const Nodes &p )const {
return aimFun>p.aimFun;
}
int calAimFun(){
int ret=sumLength*2;
int min1=INF,min2=INF;
for(int i=0;i<city.m_iCount;++i){
if(visitedCity[i]==0 && min1>weight[i][startCity]){
min1=weight[i][startCity];
}
}
for(int i=0;i<city.m_iCount;++i){
if(visitedCity[i]==0 && min2>weight[endCity][i]){
min2=weight[endCity][i];
}
}
ret+=(min1+min2);
for(int i=0;i<city.m_iCount;++i){
if(visitedCity[i]==0){
min1=INF;
min2=INF;
for(int j=0;j<city.m_iCount;++j){
if(min1>weight[i][j]){
min1=weight[i][j];
}
}
for(int j=0;j<city.m_iCount;++j){
if(min2>weight[j][i]){
min2=weight[j][i];
}
}
ret+=(min1+min2);
}
}
return ret%2==0?ret/2:(ret/2+1);
}
};
//优先队列,比较大小然后输出最先的值
priority_queue<Nodes> q;
void input(){
scanf("%d",&city.m_iCount);
for(int i=0;i<city.m_iCount;++i){
for(int j=0;j<city.m_iCount;++j){
if(i==j)
weight[i][j]=INF;
else
cin>>weight[i][j];
}
}
}
//确定下界
int getDownWeight(){
int downWeight=0;
int temp[city.m_iCount];
for(int i=0;i<city.m_iCount;++i){
memcpy(temp,weight[i],sizeof(temp));
sort(temp,temp+city.m_iCount);
downWeight+=(temp[0]+temp[1])/2;
}
return downWeight;
}
//贪心法确定上界
int dfs(int now_p,int count,int sumLength){
if(count==city.m_iCount-1){
return sumLength+weight[now_p][0];
}
int min=INF;
int next_p=-1;
for(int i=0;i<city.m_iCount;++i){
if(city.visitedCitys[i]==0&&min>weight[now_p][i]){
min=weight[now_p][i];
next_p=i;
}
}
city.visitedCitys[next_p]=1;
return dfs(next_p,count+1,sumLength+min);
}
int getUpWeight(){
memset(city.visitedCitys,0,sizeof(city.visitedCitys)); //标记已走过的城市
city.visitedCitys[0]=1;
return dfs(0,0,0);
}
int solve(){
city.m_iUpWeight=getUpWeight();
city.m_iDownWeight=getDownWeight();
Nodes node;
node.aimFun=city.m_iDownWeight;
int ret=INF;
q.push(node);
while(!q.empty()){
Nodes temp=q.top();
//cout<<"拿出:"<<temp.endCity<<endl;
q.pop();
if(temp.numbers==city.m_iCount-1){
int p=-1;
for(int i=0;i<city.m_iCount;++i){
if(0==temp.visitedCity[i]){
p=i;
break;
}
}
int ans=temp.sumLength+weight[temp.endCity][p]+weight[p][temp.startCity];
Nodes judge=q.top();
if(ans<=judge.aimFun){
ret=min(ans,ret);
break;
}else{
city.m_iUpWeight=min(city.m_iUpWeight,ans);
ret=min(ret,ans);
continue;
}
}
Nodes next;
for(int i=0;i<city.m_iCount;++i){
if(temp.visitedCity[i]==0){
next.endCity=i;
next.startCity=temp.startCity;
next.numbers=temp.numbers+1;
next.sumLength=temp.sumLength+weight[temp.endCity][i];
for(int k=0;k<city.m_iCount;++k)next.visitedCity[k]=temp.visitedCity[k];
next.visitedCity[i]=1;
next.aimFun=next.calAimFun();
//cout<<next.endCity<<" 的目标函数是 "<<next.aimFun<<endl;
if(next.aimFun>=city.m_iUpWeight)continue;
q.push(next);
//cout<<next.endCity<<" 添加"<<endl;
}
}
}
return ret;
}
int main(){
memset(weight,0,sizeof(weight));
input();
city.m_iDownWeight=getDownWeight();
city.m_iUpWeight=getUpWeight();
//cout<<"city.m_iDownWeight "<<city.m_iDownWeight<< "city.m_iUpWeight "<<city.m_iUpWeight<<endl;
int ret=solve();
//cout<<"最优解为:"<<endl;
cout<<ret<<endl;
return 0;
}