您的位置:首页 > 其它

单源最短路径

2017-09-08 14:48 78 查看

单源最短路径的种种…

DP的算法

单源最短路径的种种
DP的算法

NO1 only 5 lines Floyd算法
优缺点

基本概念

代码

NO2 Dijksra 算法
优缺点

基本概念

代码 On2

代码 复杂度On logn

NO3 Bellman-Ford 算法
声明

优缺点

基本思路

算法的过程

OR 队列优化的Bellaman

NO.1: only 5 lines – Floyd算法

优缺点:

*优点:

1.可以处理负权值的图

2.算法简单!

缺点:

1.无法处理负权环的情况!

2. 三重循环,无法算大的数据.*

基本概念:

就是将每次设置一个k点作为中转站,在用1~n的i与j二重循环来套进去,利用一个矩阵来储存,如a[i][j]表示i->j的权值. 对每一个点进行松弛,看是否成功!

转移方程:

if(a[i][k]<inf&&a[k][j]<inf&&a[i][k]+a[k][j]<a[i][j])
a[i][j]=a[i][k]+a[k][j];


代码:

#include<stdio.h>
#include <iostream>
using namespace std;
int main() {
int a[100][100],n,m,t1,t2,value;
int inf=999999;
cin>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(i==j) a[i][j]=0;
else a[i][j]=inf;
cin>>m;
for(int i=1; i<=m; i++) {
cin>>t1>>t2>>value;
a[t1][t2]=value;
}
// Floyd-warshall 算法核心
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(a[i][k]<inf&&a[k][j]<inf&&a[i][k]+a[k][j]<a[i][j]) a[i][j]=a[i][k]+a[k][j];

for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++)
if(a[i][j]==inf) cout<<"∞";
else printf("%3d",a[i][j]);
cout<<endl;
}
}


NO.2: Dijksra 算法

优缺点:

优点:

1.没有三重循环!

2.复杂度小

3.基于贪心策略!

缺点:1.无法处理负权值(因为会破坏确定值不变的情况)

基本概念:

就是每次找一个离一号点最近而且没有处理过的数字(book[ ]来储存是否操作)

来将其作为”中转站”来松弛其他的点!用一个dis[ ]数组来储存值!

找最小点的代码:

min=inf;
for(j=1;j<=n;j++)
{
if(book[j]==0 && dis[j]<min)
{
min=dis[j];
u=j;
}
}


代码 –O(n^2):

#include <stdio.h>
int main()
{
int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
//读入n和m,n表示顶点个数,m表示边的条数
scanf("%d %d",&n,&m);

//初始化
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;

//读入边
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
}
//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
for(i=1;i<=n;i++)
dis[i]=e[1][i];
//book数组初始化
for(i=1;i<=n;i++)
book[i]=0;
book[1]=1;

//Dijkstra算法核心语句
for(i=1;i<=n-1;i++)  //每次循环定位一个数
{
//找到离1号顶点最近的顶点
min=inf;
for(j=1;j<=n;j++)
{
if(book[j]==0 && dis[j]<min)
{
min=dis[j];
u=j;
}
}
book[u]=1;
for(v=1;v<=n;v++)
{
if(e[u][v]<inf)
{
if(dis[v]>dis[u]+e[u][v])
dis[v]=dis[u]+e[u][v];
}
}
}

//输出最终的结果
for(i=1;i<=n;i++)
printf("%d ",dis[i]);

getchar();
getchar();
return 0;
}


代码 –复杂度O(n logn)

#include <iostream>
#include <stdio.h>
#include <algorithm>
e9f6
;
#include <queue>
#include <vector>
using namespace std;
typedef  long long ll;
typedef pair<ll,ll> P;
const int N=1000005;
const int inf=999999;
struct edge
{
int to,cost;
bool road;
edge(bool road,ll to=0,ll cost=0):road(road),to(to),cost(cost) {}
};
int n,m,k;
vector<edge> G
;
ll d
;
void dijstra(long long  s)
{
//С¸ù¶ÑµÄ×ö·¨!
priority_queue<P,vector<P>,greater<P> > que;
fill(d,d+n,inf);
d[1]=0;
que.push(P(0,1));
while(!que.empty())
{
P p=que.top();
que.pop();
int v=p.second;

if(d[v]<p.first) continue;
for(int i=0; i<G[v].size(); i++)
{
edge e=G[v][i];
if(d[e.to]>d[v]+e.cost)
d[e.to]=d[v]+e.cost;
que.push(P(d[e.to],e.to));
}

}
}
int main()
{
//......
return 0;
}


NO.3: Bellman-Ford 算法

声明:

如有雷同,纯属巧合,请勿介意!

优缺点:

优点:

1.可以判断负权回路

2.好像可以处理环哦!

3.简易易学(啊哈!)

缺点:

1.我觉得挺好的!

基本思路:

将原来1->i的点局设置为∞,在之后的m-1轮之中可以将其松弛,

就是看

k==1->1点通过1条边能够到达的最小

k==2->1点通过2条边能够达到的最小

……

k==n->1点…..n…最小

即:

for(int k=1; k<=n-1; k++) //n-1条边的分别确定 即k->k条边
for(int i=1; i<=m; i++)
if(dis[v[i]]>dis[u[i]]+w[i])
dis[v[i]]=dis[u[i]]+w[i];


所以说就是每次循环找出所有输入边的情况,在进行操作k-1轮!

算法的过程:

#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int n,m,dis[1000],u[1000],v[1000],w[1000];
int inf=999999;
cin>>n>>m;

for(int i=1; i<=m; i++)
cin>>u[i]>>v[i]>>w[i];

for(int i=1; i<=n; i++)
dis[i]=inf;
dis[1]=0;

//Bellman-Ford 算法的核心;
for(int k=1; k<=n-1; k++) //n-1条边的分别确定 即k->k条边 for(int i=1; i<=m; i++) if(dis[v[i]]>dis[u[i]]+w[i]) dis[v[i]]=dis[u[i]]+w[i];

for(int i=1; i<=n; i++)
cout<<dis[i]<<" ";

}
/*
测试数据附赠:
Input:
5 5
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3
Output:
0 -3 -1 2 4
*/


OR 队列优化的Bellaman

#include <stdio.h>
#include <iostream>
using namespace std;
int main() {
int n,m;
int u[10],v[10],w[10];
int first[10],next[10];
int dis[6]= {0},book[6]= {0};
int que[101]= {0},head=1,tail=1;
int inf=9999999;

cin>>n>>m;

for(int i=1; i<=n; i++)
dis[i]=inf;
dis[1]=0;

//³õʼ»¯bookÊý×é,Ò»¿ªÊ¼Îª0,±íʾ¾ù²»ÔÚ¶ÓÁÐÖÐ
for(int i=1; i<=n; i++)
book[i]=0;

//½«ÁÚ½Ó±í³õʼ»¯Îª-1 ,±íʾÔÝʱ¶¼Ã»Óб߼ÓÈë
for(int i=1; i<=n; i++)
first[i]=-1;

for(int i=1; i<=m; i++) {
//¶ÁÈëÿһÌõ±ß
cin>>u[i]>>v[i]>>w[i];
next[i]=first[u[i]];
first[u[i]]=i;

}
//1ºÅµãÈë¶Ó
que[tail]=1;
tail++;
book[1]=1;//±íʾÈë¶Ó
int k;
while(head<tail) {
k=first[que[head]];//¶ÓÊ×µÄÊý¾Ý
while(k!=-1) {
if(dis[v[k]]>dis[u[k]]+w[k])
dis[v[k]]=dis[u[k]]+w[k];
//ÓÃÒ»¸öbookÊý×éÅжÏÊÇ·ñÔÚ¶ÓÁÐÀï
if(book[v[k]]==0)
//Èç¹û²»Ê¹ÓÃbookÀ´¼Ç¼¾ÍҪÿ´Î´Óhead~tailɨһ±é!
{
que[tail]=v[k];
tail++;
book[v[k]]=1;//±íʾv[k]ÒѾ­ÈëÁÐ
}
k=next[k];
}
//³ö¶Ó
book[que[head]]=0;
head++;
}
for(int i=1; i<=n; i++)
printf("%d ",dis[i]);
return 0;

}


注:如有兴趣,请加关注哦!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法 dp