グラフ理論のアルゴリズムのトレーニング_最短経路アルゴリズム
シングルソース最短経路問題
BFSアルゴリズムは、以下に、重み付けされたグラフの最短経路問題を解くことができない
> A - - > C -単一ソース最短SであるべきであるBにS > B、 BFSを使用した場合、エラーが発生しました。
ダイクストラ法
スコープ:にのみ適用非負の重み付きグラフ。
開始点S、S 0ポイント、正の無限大の残りのポイント1.。
A 7、B 5を作製2.更新S隣接するドット、及びポイントをマークS.
B.標識された5 3点Bに隣接する最小更新点、C 6及び点
4.点A 7、C点6、Cが最小の点である、点Aは0更新され、点C、点Aマーク最後アルゴリズム終了をマークします。
> C-> - > A -この時点で見出さ、点Bへの最短点はSであるべきであるS B、 代わりに5から、経路2。
の隣接リストを達成するために、ダイクストラ法
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1001;
const int M = 10001;
int n ,m;
struct edge
{
int v , w , next; //v是连向顶点的编号,w是边的权重,next表示这条边的下一条边的编号
edge(){}
edge(int _v , int _w , int _next)//结构体里的构造函数
{
v = _v;
w = _w;
next = _next;
}
}e[M*2]; //e存放的每一条边
int head[N] , size;
void init()
{
memset(head , -1 , sizeof(head));
size = 0;
}
void insert(int u , int v ,int w)
{
e[size] = edge(v , w , head[u]); //head[u]当前u连出的第一条边
head[u] = size++;
}
void insert2(int u , int v , int w)
{
insert(u , v , w);
insert(v , u , w);
}
int dis[N]; //原点到每一个点的最短路径
bool vis[N]; //点是否被标记过
void dijkstra(int u)
{
memset(vis , false , sizeof(vis));
memset(dis , 0x3f , sizeof(dis)); //dis初始化为正无穷
dis[u] = 0;
for(int i = 0 ; i < n ; i++) //找n次没有标记过的点
{
int mind = 10000000000 , minj = -1;
for(int j = 1 ; j <= n ;j++)
{
if(!vis[j] && dis[j] < mind) //如果点没有被标记且j位置路径小于最小值 ,则更新
{
minj = j;
mind = dis[j];
}
}
if(minj == -1) return; //没有找到标记的点,不是连通图,返回
vis[minj] = true;
for(int j = head[minj] ; ~j ; j = e[j].next) // j != -1 遍历minj出发的每条边
{
int v = e[j].v;
int w = e[j].w;
if(!vis[v] && dis[v] > dis[minj] + w)
{
dis[v] = dis[minj] + w;
}
}
}
}
int main()
{
init();
int u , v ,w;
cin >> n ; //求1->n中的最短路,m是输入数据行数
for(int i = 2 ; i <= n ; i++)
{
for(int j = 1 ; j < i ; j++)
{
cin >> w;
insert2(i , j , w);
}
}
dijkstra(1);
cout << dis[n] << endl;
return 0 ;
}
ダイクストラのアルゴリズムの最適化を達成ヒープ
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 1001;
const int M = 10001;
int n ,m;
struct edge
{
int v , w , next; //v是连向顶点的编号,w是边的权重,next表示这条边的下一条边的编号
edge(){}
edge(int _v , int _w , int _next)//结构体里的构造函数
{
v = _v;
w = _w;
next = _next;
}
}e[M*2]; //e存放的每一条边
struct Node{
int v , d;
Node(int v , int d):v(v) , d(d){}
bool operator < (const Node &w)const{
return d > w.d;
}
};
int head[N] , size;
void init()
{
memset(head , -1 , sizeof(head));
size = 0;
}
void insert(int u , int v ,int w)
{
e[size] = edge(v , w , head[u]); //head[u]当前u连出的第一条边
head[u] = size++;
}
void insert2(int u , int v , int w)
{
insert(u , v , w);
insert(v , u , w);
}
int d[N];
bool vis[N]; //点是否被标记过
void dijkstra(int u)
{
//memset(vis , false , sizeof(vis));
memset(d , 0x3f , sizeof(d)); //dis初始化为正无穷
d[u] = 0;
priority_queue<Node> q;
q.push(Node(u , 0));
while(!q.empty())
{
u = q.top().v;
q.pop();
if(vis[u]) continue;
for(int j = head[u] ; ~j ; j = e[j].next) // j != -1 遍历minj出发的每条边
{
int v = e[j].v;
int w = e[j].w;
if(!vis[v] && d[v] > d[u] + w)
{
d[v] = d[u] + w;
q.push(Node(v , d[v]));
}
}
}
}
int main()
{
init();
int u , v ,w;
cin >> n >> m; //求1->n中的最短路,m是输入数据行数
while(m--)
{
cin >> u >> v >> w;
insert2(u , v , w);
}
dijkstra(1);
cout << d[n] << endl;
return 0 ;
}
SPFAアルゴリズム(図負算出右)
出発点、1,2,5-エンキュー数、キュー(125)として0番、1番、この時点で2であり、2番は5であり、IIIは無限大であり、図4は無限であり、第5号であります9
3,1、3がエンキューデキューシーケンス番号は、この時点でキュー(253)、1番は2である更新、2号は5であり、IIIは1であり; 4は無限である; 9番5される
更新します次いで、米国特許第デキュー4,2、4がエンキュー、キュー(534)、
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e3 +9;
const int M = 1e4 +9;
const int inf = 0x3f3f3f3f;
int dis[N] , in[N];
bool vis[N];
int n , m;
struct edge{
int v , w , next;
edge(){}
edge(int _v , int _w ,int _next)
{
v = _v;
w = _w;
next = _next;
}
}e[M << 1]; //M*2
int head[N] , len;
void init()
{
memset(head , -1 , sizeof(head));
len = 0;
}
void add(int u , int v ,int w)
{
e[len] = edge(v , w , head[u]);
head[u] = len++;
}
void add2(int u , int v ,int w)
{
add(u , v , w);
add(v , u , w);
}
/*bool*/void spfa(int u)
{
memset(vis , false , sizeof(vis));
vis[u] = true;
memset(dis , 0x3f , sizeof(dis));
dis[u] = 0;
//memset(in , 0 ,sizeof(in)); in[u] = 1;
queue<int> q;
q.push(u);
while(!q.empty())
{
u = q.front();
q.pop();
vis[u] = false;
for(int j = head[u] ; ~j ; j = e[j].next)
{
int v = e[j].v;
int w = e[j].w;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if(!vis[v])
{
q.push(v);
vis[v] = true;
//++in[v]; if(in[v] > n) return true;
}
}
}
}
//return false;
}
int main()
{
init();
int u , v , w;
cin >> n >> m;
while(m--)
{
cin >> u >> v >> w;
add2(u , v , w);
}
spfa(1);
cout << dis[u] << endl;
/*if(spfa(1)) //判断是否有负环
{
cout << "Yes" << endl;
}else
cout << "No" << endl;
*/
return 0;
}
マルチソース最短パスアルゴリズム
任意の2点間の最短経路
フロイドのアルゴリズム(負側の右隣のテーブルすることなく使用することができません)
重み付けされたグラフに与えられた二つの頂点間の最短経路を計算するための動的プログラミングアルゴリズムを使用することを考えました。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 205, inf = 0x3f3f3f3f;
int g[N][N] , n , m;
void floyd(){
for(int k = 0 ; k <= n ; k++)
{
for(int i = 0 ; i <= n ; i++)
{
for(int j = 0 ; j <= n ; j++)
{
g[i][j] = min(g[i][j] , g[i][k] + g[k][j]);
}
}
}
}
int main()
{
while(cin >> n >> m)
{
memset(g , 0x3f , sizeof(g));//floyd算法起手需要所有点为正无穷,自身点到自身距离为0
for(int i = 1 ; i <= N; i++)
{
g[i][i] = 0;
}
int u , v , w ,s ,t;
while(m--)
{
cin >> u >> v >> w;
u++,v++;
g[u][v] = g[v][u] = min(g[u][v] , w); //自己到自己的距离应该为0
}
floyd();
cin >> s >> t;
s++,t++;
if(g[s][t] > inf/2) cout << "-1" << endl; //判断是否有从起点到终点的路线
else cout << g[s][t] <<endl;
}
return 0;
}
//HDU1874