順便複習了類的繼承,派生類的寫法如下:
Derive (int _cl, int _rl, int _zl, int _id):Base(_cl, _id),rl(_rl),zl(_zl){}
注意,
1.基類的構造函數Base() 的兩個參數是實參,Derive的形參傳遞給Base(),就是實參.如果寫成Base(3,5),也不出錯.
2.基類構造函數的調用放在函數頭部,不能放在函數體{}中。
一.問題描述
優先隊列中,zl=cl+rl作爲優先級
cl:當前走過的路程.
rl:剩餘的路徑長度 擁剩餘每個結點的最小出邊之和. 例如有一表示1,2,3,4 四個城市的矩陣:
{INF,15,30,5}, min=5
{15,INF,6,12}, min=6
{30,6,INF,3}, min=3
{5,12,3,INF } min=3
初始時,剩餘4個城市 rl=5+6+3+3=17 (注意,不同結點的最小出度可能相同)
二.代碼實現
1.全局變量區,有一部分繼承自TCP.h,(詳見文章上一篇)
#include"TSP.h" //繼承全局變量和結構體State2
int minsum; //記錄剩餘節點的最小出路之和
int minout[N3]; //記錄各個結點的最小出路
//記錄狀態
struct State3: public State2
{
int rl;
int zl;
State3() {};
State3(int _cl, int _rl, int _zl, int _id):State2(_cl, _id),rl(_rl),zl(_zl){}
//zl越小的,優先級越大
friend bool operator<(const State3& a, const State3& b)
{
return a.zl > b.zl;
}
};
2.Bound()下界函數,作用有二:
(1)當某個結點和其它所有結點都不連通時,判定爲false
(2)記錄各結點的最小出度 和 所有結點的最小出度之和.記錄在minout[] 和minsum.
問題在於,優先級zl = cl + rl. cl 還好理解, rl 的初始值=minsum; 每拓展出一個結點,rl -= minout[ i ]
另外,活結點的約束條件是 if(zl<bestp)
最小出度之和爲什麼能決定優先級和限界條件?
網上找不到對這個下界函數的解釋.如果你有想法請評論.
bool Bound() {
for (size_t i = 0; i <N3; i++)
{
int minl = INF;
for (size_t j = 0; j < N3; j++)
{
if (T3[i][j] != INF && T3[i][j] < minl)
{
minl = T3[i][j];
}
}
if (minl==INF)//未找到聯通路徑
{
return false;
}
minout[i] = minl;
minsum += minout[i];
}
return true;
}
3.遍歷函數
第一次運行時忘了加pop()彈出隊首元素
double TravelingBFS_2()
{
if (!Bound())
{
cout << "無可行解" << endl;
return -1;
}
//循環前的初始化準備
State3 livenode, newnode;
newnode = State3(0, minsum, minsum, 1); //minsum已在之前調用的Bound()中算出
for (size_t i = 0; i < N3; i++)
newnode.x[i] = i;
priority_queue<State3> q;
q.push(newnode);
//開始循環
while (!q.empty())
{
livenode = q.top();
q.pop();
int t = livenode.id;
//活結點的終止循環(約束)條件
if (t == N3 - 1) //到達倒數第二個結點
{
if (T3[livenode.x[0]][livenode.x[N3 - 1]] != INF && //最後一個城市和起點城市有連接
T3[livenode.x[N3 - 1]][livenode.x[N3 - 2]] != INF && //倒數第二個城市和最後一個城市有連接
livenode.cl + T3[livenode.x[N3 - 2]][livenode.x[N3 - 1]] + T3[livenode.x[0]][livenode.x[N3 - 1]] < bestp3
//相加後 < 目前最優值
)
{
bestp3 = livenode.cl + T3[livenode.x[N3 - 2]][livenode.x[N3 - 1]] + T3[livenode.x[0]][livenode.x[N3 - 1]];//更新
bestx3 = livenode.x;
}
continue; //到達倒二結點已經求出一個bestx[],或已知不存在最佳順序,必須跳出本次循環
}
//活結點的限界條件
if (livenode.cl >= bestp3)
continue;
//開始遍歷分支結點
for (size_t i = t; i < N3; i++)
{
if (T3[livenode.x[t-1]][livenode.x[i]]!=INF)//約束條件:當前結點和下一個待測節點有鏈接
{
int cl = livenode.cl + T3[livenode.x[t - 1]][livenode.x[i]];
int rl = livenode.rl - minout[livenode.x[i]];
int zl = cl + rl;
if (zl < bestp3)
{
newnode = State3(cl, rl, zl, t + 1);
newnode.x = livenode.x;
swap(newnode.x[t], newnode.x[i]);//t來自livenode.id,是livenode狀態要處理的下一個結點序號,顯然要換成i
q.push(newnode);
}
}
}
}
return bestp3;
}
4.初始化&調用函數
void TSP_2() {
//初始化
bestp3 = INF;
bestx3.resize(N3, 0);
minsum = 0;
//遍歷
cout << "最短距離爲: " << TravelingBFS_2();
cout << endl;
cout << "最優旅行順序: ";
for (int i = 0; i < N3; i++)
{
cout << bestx3[i] << "-";
}cout << "0";
}
三.Bug分析
1.在源.cpp調用TSP_2(),什麼顯示都沒有,連距離爲 "字樣都沒打印出來.
而且無法選擇其它選項,說明程序陷入死循環,無法結束運行 <- 優先隊列一直不爲空 <- 忘記加pop()出隊已有的元素.