代码比较简洁,没有类,也没有用到动态申请内存,对小白蛮友好的。看到了许许多多的题解,感觉对小白不友好,所以本菜站了出来 如果有啥子问题,希望能提出来改正。毕竟这是本小白第一篇题解
思路
对于图G=(V,E),假设从顶点i出发,V’= V - i,则d(i,V’)表示从顶点i出发经过V’中各个顶点一次仅一次,最后回到顶点i的最短路径长度,初始子问题就是d(k,{})表示点k到顶点i的距离。
现在考虑原问题的一部分,d(k,V’-{k})表示从顶点k出发经过V’-{k}中各个点一次仅一次,最后回到出发点i的最短路径长度,则:
d(k,{}) = cki;
d(i,V’) = min(cik + d(k,V’- {k}))(k ∈V’)
(3)从0城市出发经城市1、2、3然后回到0城市的最短路径长度是:
d(0,{1, 2, 3})=min{c01+d(1, { 2, 3}), c02+d(2, {1, 3}), c03+d(3, {1, 2})}
这是最后一个阶段的决策,而:
d(1, {2, 3})=min{c12+d(2, {3}), c13+ d(3, {2})}
d(2, {1, 3})=min{c21+d(1, {3}), c23+ d(3, {1})}
d(3, {1, 2})=min{c31+d(1, {2}), c32+ d(2, {1})}
这一阶段的决策又依赖于下面的计算结果:
d(1, {2})= c12+d(2, {}) d(2, {3})=c23+d(3, {})
d(3, {2})= c32+d(2, {}) d(1, {3})= c13+d(3, {})
d(2, {1})=c21+d(1, {}) d(3, {1})=c31+d(1, {})
而下式可以直接获得(括号中是该决策引起的状态转移):
d(1, {})=c10=5(1→0) d(2, {})=c20=6(2→0) d(3, {})=c30=3(3→0)
然后逆推就可得出最短路径。
上代码
#include
using namespace std;
int l[20][20],d[20][1000];//l位代价矩阵,d为状态矩阵
int main()
{
int n,i,j,k;//n个城市
cin >> n;
for(i = 0;i < n; ++i)//构造代价矩阵
{
for(j = 0;j < n; ++j)
{
cin >> l[i][j];
if(i == j) l[i][j] = 0xffff;
//自己到自己的距离肯定是无穷大啊
//所以最难到达的地方是自己啊
}
}
for(i = 1;i < n; ++i)
d[i][0] = l[i][0];
for(j = 1;j < 1 << (n - 1); ++j)
//用二进制来压缩状态
{
for(i = 0;i < n; ++i)
{
d[i][j] = 0xffff;
//初始距离为很大
for(k = 1;k != n; ++k)
//判断k城市是否在集合中
if(j >> (k - 1) & 1)//k如果在集合中
//位运算和与运算了解一下
d[i][j] = min(d[i][j],d[k][j ^ 1 << (k - 1)] + l[i][k]);
//以k为中间节点寻找最后面最短的路径
}
}
cout << "打表:" << endl;
for(i = 0;i < n; ++i)
{
for(j = 0;j < 1 << (n - 1); ++j)
cout << d[i][j] << " ";
cout << endl;
}
cout << "最短路径为:" << d[0][1 << (n - 1) - 1] << endl;
}
/*这是测试数据,0在这里这是为了使输入方便一点
4
0 3 6 7
5 0 2 3
6 4 0 2
3 7 5 0
*/