四、实验内容
一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。
五、算法描述及实验步骤
1.关于分支限界,本次选用了优先队列,通过重写排序函数来对队列的优先级进行定义,从而每次在队头得到自己想要的数据。
2.关于存图,在一开始打算使用邻接表,后来发现这类题型一般都是每个城市之间都有直接通路,所涉及的条数比较多,属于稠密图,所以后来改成了邻接矩阵进行存图。
3.关于剪枝函数,是考虑了顶点的费用下界,当前费用加上还没有考虑到的点最小出边费用之和,当遍历到某个点发现该点的费用下界比全局最优值大的时候就进行剪枝,剪掉该子树。
4.关于更新最优值,当更新了该顶点之后还差一个就遍历完全部点时,这个点的最优值(费用下界)为当前费用加上该点到最后一个点的费用再加上最后一个点到初始点的费用。求出值之后,如果该值比全局的最优值还要小,则更新最优值,这样就不用考虑到叶子节点了。
5.关于while循环的终止,当优先队列的头节点为次叶子节点(即叶子节点的父节点)时,就是此时的最优值就是答案,终止循环,输出路径。
代码仅供参考
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e2+5;
const int inf=0x3f3f3f3f;
typedef pair<int,int> pii;
int n,m;
int minout[maxn];//顶点i的最小费用出边
int mp[maxn][maxn];
int sum;//所有顶点的最小费用出边之和。
int bestc=inf;//最优结果
/*
4
-1 30 6 4
30 -1 5 10
6 5 -1 20
4 10 20 -1
*/
struct node
{
int lcost;//费用下界 当前节点费用 加上 总的最小费用减去上一次路径中的顶点费用之和
int s;//路径中有多少个顶点
int sumz;//当前结点的费用
vector<int>x;//存放路径
int sumx;//当前路径中的顶点的最小出边费用之和
int far;//父节点
};
struct cmp1
{
bool operator ()(node a, node b)
{
return a.sumx>b.sumx;
}
};
void solve(int u)
{
node start;
start.sumx=minout[u];
start.sumz=0;
start.lcost=start.sumz+sum-0;
start.x.push_back(u);
start.s=1;
start.far=-1;
priority_queue<node,vector<node>,cmp1>pq;
pq.push(start);
while(!pq.empty())
{
auto temp=pq.top();
pq.pop();
if(temp.s==n-1)
{
bestc=temp.lcost;
cout<<bestc<<endl;
// cout<<"路径:"<<endl;
vector<int>falg(n,0);
for(int i=0; i<temp.s; i++)
{
cout<<temp.x[i]<<" ";
falg[temp.x[i]]=1;
}
for(int i=1; i<=n; i++)
{
if(falg[i]==0)
{
cout<<i<<" 1"<<endl;
}
}
break;
}
u=temp.x[temp.s-1];
for(int v=1;v<=n;v++)
{
if(v==u)continue;
int fff=0;
for(int i=0; i<temp.s; i++)
{
if(temp.x[i]==v)
{
fff=1;
break;
}
}
if(fff)
continue;
int w=mp[u][v];
node next;
next.s=temp.s+1;
next.x=temp.x;
next.x.push_back(v);
next.far=u;
next.sumz=temp.sumz+w;
next.sumx=temp.sumx+minout[v];
if(next.s<n-1)
{
next.lcost=next.sumz+sum-temp.sumx;
if(bestc>next.lcost) //更新
{
pq.push(next);
}
}
else
{
int t=0;
for(int i=0; i<next.s; i++)
{
t+=next.x[i];
}
t=(1+n)*n/2-t;
//cout<<"t:"<<t<<endl;
next.lcost=next.sumz+mp[v][t]+mp[t][1];
//cout<<"mp[v][t]"<<mp[v][t]<<endl;
if(bestc>next.lcost)
{//cout<<next.lcost<<endl;
bestc=next.lcost;
pq.push(next);
}
}
}
}
}
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
{
minout[i]=inf;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
cin>>mp[i][j];
if(mp[i][j]!=-1)
{
minout[i]=min(minout[i],mp[i][j]);
}
}
for(int i=1; i<=n; i++)
sum+=minout[i];
//cout<<sum<<endl;
solve(1);
return 0;
}