Pentium.Labs

System全家桶:https://zhuanlan.zhihu.com/c_1238468913098731520

导航

dijkstra,SPFA,Floyd求最短路

Dijkstra:

裸的算法,O(n^2),使用邻接矩阵:

算法思想:

定义两个集合,一开始集合1只有一个源点,集合2有剩下的点。

STEP1:在集合2中找一个到源点距离最近的顶点k:min{d[k]}

STEP2:把顶点k加入集合1中,同时修改集合2中的剩余顶点j的d[j]是否经过k之后变短,若变短则修改d[j];

if d[k]+a[k,j]<d[j] then   d[j]=d[k]+a[k,j];

STEP3:重复STEP1,直到集合2为空为止。

#include <iostream>
#include <cstring>
using namespace std;
#define MAXINT 9999999

int minx,minj,x,y,t,k,n,m,tmp;
int v[1000],d[1000],a[1000][1000];

int main()
{
    cin>>n>>m>>k;
    memset(a,0,sizeof(a));
    memset(d,MAXINT,sizeof(d));
    memset(v,0,sizeof(v));
    d[k]=0;
    for (int i=1;i<=m;i++)
    {
        cin>>x>>y>>t;
        a[x][y]=t;
        a[y][x]=t;
    }

    for (int i=1;i<=n-1;i++)
    {
        minx=MAXINT;
        for (int j=1;j<=n;j++)
            if ((v[j]==0)&&(d[j]<minx))
            {
                minx=d[j];
                minj=j;
            }
        v[minj]=1;
        for (int j=1;j<=n;j++)
            if ((v[j]==0)&&(a[minj][j]>0))
            {
                tmp=d[minj]+a[minj][j];
                if (tmp<d[j])   d[j]=tmp;
            }
    }

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

    return 0;
}
View Code

 

Tips:上述STEP1可以用优先队列优化

模版:

(使用邻接表,Reference:http://www.cnblogs.com/qijinbiao/archive/2012/10/04/2711780.html)

eg:邻接表

i:某条边的起点  eg[i][j].x:从点i出发的第j条边的终点  eg[i][j].d:这条边的距离

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int Ni = 10000;
const int INF = 1<<27;
struct node{
    int x,d;
    node(){}
    node(int a,int b){x=a;d=b;}
    bool operator < (const node & a) const
    {
        if(d==a.d) return x<a.x;
        else return d > a.d;
    }
};
vector<node> eg[Ni];
int dis[Ni],n;
void Dijkstra(int s)
{
    int i;
    for(i=0;i<=n;i++) dis[i]=INF;
    dis[s]=0;
    priority_queue<node> q;
    q.push(node(s,dis[s]));
    while(!q.empty())
    {
        node x=q.top();q.pop();
        for(i=0;i<eg[x.x].size();i++)
        {
            node y=eg[x.x][i];
            if(dis[y.x]>x.d+y.d)
            {
                dis[y.x]=x.d+y.d;
                q.push(node(y.x,dis[y.x]));
            }
        }
    }
}
int main()
{
    int a,b,d,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<=n;i++) eg[i].clear();
    while(m--)
    {
        scanf("%d%d%d",&a,&b,&d);
        eg[a].push_back(node(b,d));
        eg[b].push_back(node(a,d));
    }
    Dijkstra(k);

    for (int i=1;i<=n;i++)
        printf("%d\n",dis[i]);

    return 0;
}
View Code

STL优先队列Reference:http://www.cnblogs.com/wanghetao/archive/2012/05/22/2513514.html

 

 

SPFA:

即用队列优化过的Bellman-Ford

( Reference:http://blog.csdn.net/niushuai666/article/details/6791765 )

Pascal代码...

var q,d:array[1..1000] of longint;
    a:array[1..1000,1..1000] of longint;
    visited:array[1..1000] of boolean;
    head,tail,s,n,dt,i,j:longint;

begin
assign(input,'spfa.in');
reset(input);

fillchar(d,sizeof(d),127 div 3);
fillchar(visited,sizeof(visited),false);
fillchar(a,sizeof(a),0);

readln(s);
d[s]:=0;
readln(n);
for i:=1 to n do
 for j:=1 to n do
  begin
  read(dt);
  a[i,j]:=dt;
  a[j,i]:=dt;
{ if dt<>0 then
   begin
   if i=s then d[j]:=dt;
   if j=s then d[i]:=dt;
   end;
  }
  end;

head:=0;
q[1]:=s;
visited[s]:=true;
tail:=1;
while head<tail do
 begin
 inc(head);
 visited[q[head]]:=false;
 for i:=1 to n do
  begin
  if (a[q[head],i]>0) and (d[q[head]]+a[q[head],i]<d[i]) then
   begin
   d[i]:=d[q[head]]+a[q[head],i];
   if not visited[i] then
    begin
    inc(tail);
    q[tail]:=i;
    visited[i]:=true;
    end;
   end;
  end;
 end;

for i:=1 to n do
 write(d[i],' ');
writeln;

close(input);
end.
View Code

 

Floyd:

多源最短路

//path[i,j]:用来输出最短路径
//floyd
var path,d:array[1..1000,1..1000] of longint;
    n,k,i,j,st,en,x,y,tmp:longint;

procedure dfs(i,j:longint);
begin
if path[i,j]>0 then
 begin
 dfs(i,path[i,j]);
 write(path[i,j],'->');
 dfs(path[i,j],j);
 end;
end;

begin
assign(input,'floyd.in');
reset(input);

fillchar(d,sizeof(d),127 div 3);

readln(n);

for i:=1 to n do d[i,i]:=0;
for i:=1 to n do
 for j:=1 to n do
  path[i,j]:=-1;

readln(st,en);
while not eof do
 begin
 readln(x,y,tmp);
 d[x,y]:=tmp;
 d[y,x]:=tmp;
 path[x,y]:=0;
 path[y,x]:=0;
 end;

for k:=1 to n do
 for i:=1 to n do
  for j:=1 to n do
   begin
   if d[i,k]+d[k,j]<d[i,j] then
    begin
    d[i,j]:=d[i,k]+d[k,j];
    path[i,j]:=k;
    end;
   end;

writeln(d[st,en]);

write(st,'->');
dfs(st,en);
writeln(en);

close(input);
end.
View Code

 

posted on 2014-07-27 15:29  Pentium.Labs  阅读(271)  评论(0编辑  收藏  举报



Pentium.Lab Since 1998