TSP
暴力枚舉法:此方法不適合城市個數>8的。時間複雜度成階乘上升
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxx 9999
int l[maxx][maxx];//存儲兩個城市之間的距離
int n;//城市數量
int min_l = maxx;//最短路徑
int sum[maxx];//標記每條路線的路程總長度
int go_city;//標記從第go_city個城市出發
int visited[maxx]; //第i個城市已經去過:visited[i]=1;反之則爲visited[i]=0;
int path_index = 1; //已經去過的城市數目。
int path[maxx][maxx];//存儲經過城市的路線
int route = 0;//存儲第幾條路線
int recursion(int index)
{
if(path_index != n)
{
for(int i=1;i <= n;i++)
{
if(visited[i] == 0)
{
visited[i] = 1;
path[route][path_index] = index;
path_index++;
recursion(i);
//回溯
path_index--;
visited[i] = 0;
}
}
}
else
{
//路線中加上最後一個城市和第一個城市(需要返回到最初的城市)
path[route][path_index] = index;
path[route][path_index + 1] = go_city;
//計算每條路線的路程總長度,並輸出路線
printf("路線%d爲:\n",route+1);
sum[route] = 0;
for(int i=1;i<=n;i++)
{
sum[route] += l[ path[route][i] ][ path[route][i+1] ];
cout << path[route][i] << " --> ";
//當route+1後,path[route][i]的前面需要保持,後面變化。
path[route+1][i] = path[route][i];
}
if(min_l > sum[route])
{
min_l = sum[route];
}
cout << path[route][n+1] << endl;
cout << "該路線總長度爲: " << sum[route] << endl;
route++;
}
return 0;
}
int main()
{
memset(visited,0,sizeof(visited));
cout << "請輸入城市數量:";
cin >> n;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
printf("請輸入%d號城市到%d號城市之間的距離:",i,j);
cin >> l[i][j];
l[j][i] = l[i][j];
}
}
cout << "請輸入您出發的城市是第幾個城市:";
cin >> go_city;
visited[go_city] = 1;
recursion(go_city);
cout << "最短路程長度爲: ";
cout << min_l << endl;
return 0;
}
動態規劃法
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxx 10000
using namespace std;
int n;//城市數量
int l[maxx][maxx];//城市之間的距離
int dp[maxx][maxx];//dp表
int menthod()
{
//給第一列賦值
for (int i = 0; i < n; i++)
{
dp[i][0] = l[i][0];
}
//給其他列賦值
for (int j = 1; j < 1 << (n - 1); j++)
{
for (int i = 0; i < n; i++)
{
dp[i][j] = 0x7ffff; //表示無窮大
//判斷是否走過該城市j,如果走過了,就continue
if (j >> (i - 1) & 1)
{
continue;
}
for (int k = 1; k < n; k++)
{
//通過位運算判斷是否需要經過k城市,不能經過k城市就continue
if ((j >> (k - 1) & 1) == 0)
{
continue;
}
//獲取dp[i][j]的最小值,(l[i][k] + dp[k][j ^ (1 << (k - 1))這個在思路上有解釋
if (dp[i][j] > (l[i][k] + dp[k][j ^ (1 << (k - 1))]))
{
dp[i][j] = l[i][k] + dp[k][j ^ (1 << (k - 1))];
}
}
}
}
return 0;
}
int main()
{
memset(dp, 0, sizeof(dp));
cout << "請輸入城市數目:";
cin >> n;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
printf("請輸入第 %d 號城市到第 %d 號城市之間的距離:", i, j);
cin >> l[i][j];
l[j][i] = l[i][j];
}
}
menthod();
cout << "最短路徑爲: " << dp[0][(1 << (n - 1))-1] << endl;
return 0;
}
此外還有遺傳算法解決TSP問題,詳見這條博客:
https://blog.csdn.net/weixin_44611644/article/details/95016984
最短路徑問題
(1)所有點到點的
原理:對邊進行“鬆弛”,v1到v3的距離 如果 大於v1 到v2+v2到v3 則更新v1-v3的最小值。
也就是說v1到v3的距離可以通過v2這個點進行更新。
Floyd:
int i,j,k;
for(k=0;k<n;k++)//代表中轉結點
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(v[i][j]<v[i][k]+v[k][j])//v[i][j]表示結點i到j的距離
v[i][j]=v[i][k]+v[k][j];
}
o(n^3)可得到所有結點之間的最短路徑長度。
核心代碼如上,鄰接矩陣的初始化和注意初始值取大數的問題。
單源最短路-迪傑斯特拉
假設一共n個點,可求得點x到剩餘n-1個點的最短路。原理相似。
每次取出距離當前點最近的點,利用相鄰點進行“鬆弛操作”更新dis數組。最終dis數組保存的值代表了結點0到剩餘結點的最短距離。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX=0x3f3f3f3f;
int map[110][110];
int dis[110];
int visit[110];
/*
關於三個數組:map數組存的爲點邊的信息,比如map[1][2]=3,表示1號點和2號點的距離爲3
dis數組存的爲起始點與每個點的最短距離,比如dis[3]=5,表示起始點與3號點最短距離爲5
visit數組存的爲0或者1,1表示已經走過這個點。
*/
int n,m;
int dijkstra()
{
int i,j,pos=1,min,sum=0;
memset(visit,0,sizeof(visit));//初始化爲0,表示開始都沒走過
for(i=1; i<=n; i++)
{
dis[i]=map[1][i];
}
visit[1]=1;
dis[1]=0;
int T=n-1;
while(T--)
{
min=MAX;
for(j=1; j<=n; j++)
{
if(visit[j]==0&&min>dis[j])
{
min=dis[j];
pos=j;
}
}
visit[pos]=1;//表示這個點已經走過
for(j=1; j<=n; j++)
{
if(visit[j]==0&&dis[j]>min+map[pos][j])//更新dis的值
dis[j]=map[pos][j]+min;
}
}
return dis[n];
}
int main()
{
int i,j;
while(cin>>n>>m)//n表示n個點,m表示m條邊
{
memset(map,MAX,sizeof(map));
int a,b,c;
for(i=1; i<=m; i++)
{
cin>>a>>b>>c;
if(c<map[a][b])//防止有重邊
map[a][b]=map[b][a]=c;
}
int sum=dijkstra();
cout<<sum<<endl;
}
return 0;
}