題目
tsp問題(旅行商問題)是指旅行家要旅行n個城市,要求各個城市經歷且僅經歷一次然後回到出發城市,並要求所走的路程最短。
這個問題迄今為止各種演算法只是求當前情況下的最優情況,無法得出統一的求解方式。
下面是兩種不同的演算法實現,注釋部分給的很詳細。
//動態規劃和貪心法求解tsp問題
#include
#include
#include
#include
using namespace std;
#define inf 1000000
/* 貪心法使用最近鄰接點策略,來求解tsp問題。
大致的思路是:
p:儲存所經歷的點的一維陣列,初始化為乙個結點即結點0,p[i]=j代表第i步是經歷第j個節點
v:儲存未經歷的點的一維陣列,初始化為除結點0外的全部結點,v[i]=i代表第i個節點,一旦某個節點被選進p,那麼該節點的值設定為inf,即v[i]=inf
path:儲存路線的,初始化為inf,path[i]=j:第i步要走的路的長度是j
鄰接矩陣中兩點之間沒有路用路經長為inf表示
1.確定好出發點
2.把出發點作為第0個點,重新對鄰接矩陣進行構造,構造成乙個以出發點為第0個點的鄰接矩陣
3.設定當前走到的結點是p
4.從v中遍歷尋找乙個最優的結點v,使得p和v的距離最近:這個判斷要包括:p和v之間有路,而且dis(p,v)<=dis(p,x),x表示v中和v不同的任意一點
5.p=p+v,v=v-v。path[i]=distance(p,v)
6.如果v不空,則執行第3步;如果v空,則程式結束。返回結果即可
*///傳入的引數中二維指標martix代表鄰接矩陣,而num代表城市的數目
void
greedpath
(double martix[
5],int num)
;int v[num]=;
for(
int i=
0;i)else
}int p[num]=;
//下面是主要**部分
/* 要考慮p和v中的頂點怎麼表示,每執行到第i步,當前的頂點p就用頂點p[i]表示,
每執行到第i步,v中的頂點就要減少i個,但是我們不知道前i-1步從v中剔除的頂點是什麼,所以每次遍歷的時候就要
再多一層遍歷,遍歷v陣列,並進行判斷:當前遍歷到的該節點沒有被剔除而且和p[i]之間有路可走而且這條路的長度是不是最小的
*/for(
int i=
0;i1;i++)}
} v[p[i+1]
]=inf;
path[i]
=min;
} path[num-1]
=martix[p[num-1]
][0]
;//輸出結果
double sumpath=0;
for(
int i=
0;i) cout<<
0<
cout<
動態規劃求解tsp問題。
大致思路是:
設目標頂點是k
p:表示儲存最優路徑情況下各個頂點,p[i]=j表示第i步走第j個節點,初始化是0
path:表示儲存最優路徑情況下,每一次需要走的路徑長度,path[i]=j表示第i次走的路徑長度是j,初始化為0
v:表示儲存還沒有走到的節點集合,初始化為v[1]=inf,v[i]=i,表示一旦頂點被走過,那麼頂點就被設定為inf,path[i]=i表示第i個頂點是i
1.確定動態規劃關係:令d(i,v)表示從頂點i開始,經歷v中的頂點(要求全部經過,而且每個頂點只能經過僅且一次)之後,到達目標頂點的最小長度。
那麼當v是空集時,則表示當前的i頂點的下乙個頂點就是目標頂點,當v中就乙個元素時,表示i到v中該頂點的距離加上v中頂點到目標頂點的距離。
d(i,v)=distance(i,k):此時v是空集
d(i,v)=min(distance(i,v)+d(v,v-v)):此時v不是空集,v表示原v中任意乙個頂點,這個就需要遍歷比較。
2.判斷v是否為空集,如果不是,那麼遍歷v中的頂點v,並比較每次遍歷求得的dis(i,v)+d(v,v-v),
找到最小值,然後把對應的頂點v作如下操作:p=p+v,v=v-v,path[i]=dis(i,v)
3.如果2中判斷的v是空集,那麼程式結束。
上述思路在實現時不好實現,因為我們無法從一開始就知道各個d(i,v)的長度大小,而每次求解時都要用到相應的d(i,v)的子結構,
當子結構最優,得到的結果最優。所以本題可以需要求得最優子結構,符合動態規劃的思想。
那麼按照上面進一步的分析,我們可以把思路進一步深入細化:
1.先求出v是空集時,各個頂點到目標頂點的d(i,v)
2.再求出v中只有乙個元素時,各個頂點到目標頂點的d(i,v),而此時得d(i,v)完全可以使用上面的v是空集時的情況求解。
3.再求出v中只有兩個元素時,各個頂點到目標頂點的d(i,v),而此時的d(i,v)完全可以使用上面兩步求出的d求解
4……最後是v中有n-1個元素時的情況,求出之後,比較並獲得最優解。
注意:每次在d(i,v)=min(distance(i,v)+d(v,v-v))時,都要做判斷,即i和v之間有路,而且v在v中。
這時,我們只剩下乙個疑慮,就是這個d(i,v)怎麼使用資料結構表示出來。
首先這個資料結構起碼是乙個二維陣列,設為d[i][j],把不同的集合看成不同的狀態,那麼d[i][j]就表示頂點i經過j狀態集合到目標頂點的長度最優值
現在考慮怎麼把j和集合對應起來。j一定是遞增的,首先有個狀態的集合即集合裡只有目標頂點時,這個狀態的集合可以不用考慮,所以不妨把它的遞增設為從1到x。
現在要求x,我們假設有n個城市,那麼v集合最大就是裡面有n-1個元素記為v(max),而v一定是v(max)的子集,那麼x就是2^(n-1),
對城市進行按數劃分,目標頂點是0,後面的從1,2,3依次到n-1,當v中只有1時,設j=1,我們發現1對應的二進位制數,從右向左數時,第乙個元素是1,
v中只有2時,設j=2,我們發現2對應的二進位制數從右向左數第二個為1,v中只有1,2時,j=3,此時3對應的二進位制數從右向左數第乙個和第二個為1,。
那麼我們按照如下處理這個集合和j的關係:
當集合中的元素是(x,y,z,m)時,存在乙個二進位制數x(2),從右向左數第x、y、z、m位是1,其餘位是0,而x(2)對應的十進位制數x(10)就是y
那麼我們把y對應的二進位制數寫出來,j對應的二進位制數有幾個1.j狀態集合就有幾個元素,按照上面的規則重新分配狀態j,然後進行處理即可。
而且根據j的依次遞增可以知道,d也是能依次求出的
*/void
orgpath
(double martix[
5],int num)
//下面是重點,要對d每一列每一列的進行操作
for(
int j=
1;j)else}}
d[i]
[j]=min;}}
} cout<
cout<<
" "<
[num1-1]
<
double bestpath=d[0]
[num1-1]
;double curbestpath=bestpath;
//下面是列印出路徑
int p[num]=;
//儲存最優路徑節點
int temp=1;
int x=0;
//表示節點
int y=num1-1;
//表示狀態y集合
int i=1;
bool visited[num]=;
//visited[i]=false表示第i個節點還沒有被訪問,為true則表示被訪問
//動態規劃逆推結果
兩種結果都是所用演算法所能給出的最優解,所以存在差異。這也從側面反映了這個問題目前沒有統一的最優解。
約瑟夫問題兩種實現方式
陣列版本 include include main int p int malloc len sizeof int printf 請輸入步長 n scanf d pace if pace 0 if pace 0 printf 請輸入進行輪數 n scanf d time printf 請輸入您想從那...
約瑟夫問題兩種實現方式
陣列版本 include include main int p int malloc len sizeof int printf 請輸入步長 n scanf d pace if pace 0 if pace 0 printf 請輸入進行輪數 n scanf d time printf 請輸入您想從那...
兩種方式實現checkBox readonly功能
今天在做開發的時候遇到了這樣乙個問題 有乙個checkbox選項是不能被改變的。但是checkbox又是沒有readonly屬性的,這個時候我就想到了另外乙個屬性disabled,但是disabled的物件是不能提交到後台的,所以這個又被排除掉了。想了想,只能新增事件來搞定了。於是在checkbox...