最短路算法小结

来源:互联网 发布:excel数据对比分析 编辑:程序博客网 时间:2024/05/21 17:02
poj1860,poj3259,poj1062,poj2253,poj1125,poj2240邻接矩阵(Adjacency Matrix):是表示顶点之间相邻关系的矩阵。http://www.cnblogs.com/twjcnblog/archive/2011/09/07/2170306.htmlhttp://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.htmlhttp://blog.csdn.net/zrjdds/article/details/6728332http://www.cnblogs.com/twjcnblog/archive/2011/09/07/2170306.htmlSTL http://blog.csdn.net/zy_dreamer/article/details/8939926SFPA http://blog.sina.com.cn/s/blog_a46817ff01015g9h.htmlhttp://www.cnblogs.com/hxsyl/archive/2012/07/01/2572334.html 115*****Dijkstra-----#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define INF 0xffffff#define M 201int cost[M][M];//路径的权值int d[M];//s到x最短距离int used[M];//点是否用过int n,m;int s,e;//start endint a,b,c;void init(int v)//初始化 cost{    for(int i=0;i<v;i++)        for(int j=0;j<v;j++)        {            cost[i][j]=INF;        }}void dj(int s){    int i,j;    for(i=0;i<=n;i++)    {        d[i]=cost[s][i];    }    used[s]=1;    d[s]=0;/* 选其余点中距离s最短的那个点开始*/    int k,p;    for(i=0;i<=n;i++)    {        int mi=INF;        for(j=0;j<n;j++)        {            if(!used[j] && mi>d[j])            {                mi = d[j];                k = j;            }        }        used[k] = true;        for(p=0;p<n;p++)        {            if(!used[p]&&d[p]>d[k]+cost[k][p])//d[ax]+d[xb]<d[ab]不断更新dis            {                d[p]=d[k]+cost[k][p];            }        }    }}int main(){    while(cin>>n>>m)    {        init(n);        for(int i=0;i<m;i++)        {            cin>>a>>b>>c;            if(cost[a][b]>c) {cost[a][b]=c;cost[b][a]=c;}//有权值的正常 没有权值的为INF        }        memset(used,0,sizeof(used));        cin>>s>>e;        dj(s);        if(d[e]<INF) cout<<d[e]<<endl;        else cout<<-1<<endl;    }    return 0;}**********************************************#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX 0x7FFFFFFF #define N 1005 int cls[N],map[N][N],vis[N],city[101],ans[101]; int m,n,p,q; /*V为源点 */ void Dijkstra(int v) {     int i,j,min,next;     /* 先用v到邻接点的距离初始化cls */     for(i=1;i<=m;i++)        cls[i]=map[v][i];     memset(vis,0,sizeof(vis));     vis[v]=1;//起点访问标志置1     for (i=1;i<m;i++)//无等号     {         min=MAX;         next=v;         /*找出离集合最近的那个点next,以及该点到集合的距离min*/         for (j=1;j<=m;j++)         {             if(!vis[j]&&cls[j]<min)             {                 next=j;                 min=cls[j];             }         }         vis[next]=1;         for (j=1;j<=m;j++)         {            /*j点没有被访问过,j点和next点之间有通路,next点到j点的距离+集合到nxt的距离<集合到j的距离*/             if(!vis[j]&&map[next][j]<MAX&&(min+map[next][j])<cls[j])                 cls[j]=cls[next]+map[next][j];         }     } } int main() {     int T,i,j;int a,b,c;int temp;     scanf("%d",&T);     while(T--)     {        temp=0x7FFFFFFF;        for(i=0;i<N;i++)            for(j=0;j<N;j++)                map[i][j]=MAX;        scanf("%d%d%d%d",&n,&m,&p,&q);        /*  部队驻扎点 */        for(i=1;i<=n;i++)            scanf("%d",city+i);         while(p--)         {             scanf("%d%d%d",&a,&b,&c);             if(map[a][b]>c)                map[a][b]=map[b][a]=c;         }         for(i=1;i<=n;i++)            {                memset(cls,0,sizeof(cls));                Dijkstra(city[i]);                ans[i]=cls[q];                //printf("%d     %d       %d\n",cls[q],ans[i],cls[n]);            }        for(i=1;i<=n;i++)            if(temp>ans[i])                temp=ans[i];        printf("%d\n",temp);     }     return 0; } /* error: invalid types `int[int]' for array subscript 变量和数组同名 */******************************************************************************************************************#include<iostream>#include<stdio.h>using namespace std;#define inf 9999999        int map[250][250];        int n,m;        int Floyd(int x,int y){int t,i,j;for(t=0; t<n; t++)    for(i=0; i<n; i++)        for(j=0; j<n; j++)            if(map[i][j]>map[i][t]+map[t][j])            {                map[i][j]=map[i][t]+map[t][j];            }if(map[x][y]==inf) return -1;else return map[x][y];}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        int a,b,v,d,f,num;        for(int i=0; i<=n; i++)            for(int j=0; j<=n; j++)                map[i][j]=map[j][i]=inf;        for(int i=0; i<n; i++) //注意同一点的权值为0,刚开始wa在这儿            map[i][i]=0;        for(int i=0; i<m; i++)        {            cin>>a>>b>>v;            if(map[a][b]>v)                map[a][b]=map[b][a]=v;        }        cin>>d>>f;        num=Floyd(d,f);        cout<<num<<endl;    }    return 0;}******************************************************************SPFA 算法大致流程是用一个队列来进行维护。初始时将源加入队列。每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。直到队列为空时算法结束。这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法SPFA——Shortest Path Faster Algorithm,它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,可以处理负边。SPFA的实现甚至比Dijkstra或者Bellman_Ford还要简单:设Dist代表S到I点的当前最短距离,Fa代表S到I的当前最短路径中I点之前的一个点的编号。开始时Dist全部为+∞,只有Dist[S]=0,Fa全部为0。维护一个队列,里面存放所有需要进行迭代的点。初始时队列中只有一个点S。用一个布尔数组记录每个点是否处在队列中。每次迭代,取出队头的点v,依次枚举从v出发的边v->u,设边的长度为len,判断Dist[v]+len是否小于 Dist[u],若小于则改进Dist[u],将Fa[u]记为v,并且由于S到u的最短距离变小了,有可能u可以改进其它的点,所以若u不在队列中,就将它放入队尾。这样一直迭代下去直到队列变空,也就是S到所有的最短距离都确定下来,结束算法。若一个点入队次数超过n,则有负权环。SPFA 在形式上和宽度优先搜索非常类似,不同的是宽度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身被改进,于是再次用来改进其它的点,这样反复迭代下去。设一个点用来作为迭代点对其它点进行改进的平均次数为k,有办法证明对于通常的情况,k在2左右。<span style="color:#339999;">/*单源最短路径的算法最常用的是Dijkstra,些算法从时间复杂度来说为O(n^2),但是面对含有负权植的图来说就无能为力了,此时Dellman-ford算法就有用了,这咱算法是采用的是动态规化的思想,但是1994年西南交通大学段凡丁发表了SPFA(Shortest Path Faster Algorithm)听这个名字就懂了,这种算法在时间上一定很快了。它是对Dellman-ford的优化,所以建议今后直接学SPFA。很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。我们用数组d记录每个结点的最短路径估计值,而且用邻接表来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且 v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。  定理3 只要最短路径存在,上述SPFA算法必定能求出最小值。在Bellman-Ford算法中,要是某个点的最短路径估计值更新了,那么我们必须对所有边指向的终点再做一次松弛操作;在SPFA算法中,某个点的最短路径估计值更新,只有以该点为起点的边指向的终点需要再做一次松弛操作只要最短路径存在,上述SPFA算法必定能求出最小值。*/#include<iostream></span>#include<algorithm>#include<queue>#include<stdio.h>#include<string.h>#define Maxn 100#define Maxm 10000#define Max 10000using namespace std;int used[Maxn],outqueue[Maxn],head[Maxn],low[Maxn],n,m;struct Edge{       int to,w,next;}edge[Maxm];int SPFA (int start){     queue<int>a;     used[start] = 1;     low[start] = 0;     a.push(start);     while (!a.empty())     {           int top = a.front();           a.pop();           outqueue[top]++;           if (outqueue[top] > n) return false;//用来判断是否有环路           for (int k = head[top]; k!= -1; k = edge[k].next)//宽搜每一条边           {               if (low[edge[k].to] > low[top] + edge[k].w)//对点进行松弛                  low[edge[k].to] = low[top] + edge[k].w;               if (!used[edge[k].to])               {                   used[edge[k].to] = 1;                   a.push(edge[k].to);               }           }     }     return true;}int main(){    while (scanf ("%d%d", &n ,&m) != EOF)    {          memset (used, 0 ,sizeof(used));          memset (head, -1 ,sizeof(head));          memset (outqueue, 0 ,sizeof(outqueue));          memset (low, Max, sizeof(low));          int k = 0;          while (m--)          {                int a,b,w;                scanf ("%d%d%d", &a, &b, &w);                edge[k].to = b;                edge[k].w = w;                edge[k].next = head[a];                head[a] = k++;          }          cout<<SPFA(1)<<endl;          if (SPFA(1))             printf ("%d\n", low[n]);          else             printf ("no\n");    }}************************************************************#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define inf 999999#define M 2001int n,m,s;int dis[M];int vis[M];int map[M][M];void init(){    for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++)        {            map[i][j]=inf;        }}//void dj(int s)//{//    int i,j,k = 0;//    int min;//    memset(vis,0,sizeof(vis));  //初始时都没被访问过//    for(i = 1; i <=n; i++)//    {//        dis[i] = map[s][i];//    }//    vis[s] = 1;  //第一个顶点即原点,被访问//    dis[s] = 0; //s到s 即为0//    for(i = 1; i < n; i++)//    {//        min = inf;//        //找到最小的//        for (j = 1; j <= n; j++)//        {//            if (!vis[j] && dis[j] < min)//            {//                min = dis[j];//                k = j;   //最小的顶点//            }//        }//        if (min == inf)//        {//            break;//        }//        vis[k] = 1; //k顶点被访问//        //这里就是比较:直接到还是转一下再到//       //我猜,你个笨蛋肯定会问:不能转多下吗?//        //答曰:从源点一个一个向外扩展,具有最优子结构。每个dis[i]都保留着从s到i的最短距离。转多下的情况把它分解开,就知道了//        for(j = 1; j <= n; j++)//        {//            if ( !vis[j] && dis[j] > dis[k] + map[k][j])//            {//                dis[j] = dis[k] + map[k][j];//            }//        }//    }//    return ;//}void dj(int s){    int i,j,k=0;    int mi;    memset(vis,0,sizeof(vis));    for(i=1;i<=n;i++)        dis[i]=map[s][i];    vis[s]=1;    dis[s]=0;    for(i=1;i<n;i++)    {        mi=inf;        for(j=1;j<=n;j++)        {            if(!vis[j]&&dis[j]<mi)            {                mi=dis[j];                k=j;            }        }        if(mi==inf)            break;        vis[k]=1;        for(j=1;j<=n;j++)        {            if(!vis[j]&&dis[j]>dis[k]+map[k][j])                {                    dis[j]=dis[k]+map[k][j];                }        }    }}int main(){    int p,q,t,w,ww;//起点 终点 所耗费的时间    int minx;    while(~scanf("%d%d%d",&n,&m,&s))    {        memset(dis,0,sizeof(dis));        init();//地图初始化        for(int i=1; i<=m; i++)        {            scanf("%d%d%d",&p,&q,&t);            if(t<map[q][p])                map[q][p]=t;//因为是把目的地看做源点 所以必须所有的点顺得反过来        }        dj(s);        scanf("%d",&w);        minx=inf;        for(int i=1; i<=w; i++)        {            scanf("%d",&ww);            if(minx>dis[ww])                minx=dis[ww];        }        if(minx!=inf)            printf("%d\n",minx);        else            printf("-1\n");    }}//void dj(int s)//{//    int i,j,k=0;//    int mi;//    memset(vis,0,sizeof(vis));//    for(i=1; i<=n; i++)//    {//        dis[i]=map[s][i];//    }//    vis[s]=1;//    dis[s]=0;//s→s为0//    for(i=1; i<n; i++)//    {//        mi=inf;//        for(j=1; j<=n; j++)//        {//            if(!vis[j]&&dis[j]<mi)//            {//                mi=dis[j];//                k=j;//            }//        }//        if(mi=inf)//            break;//        vis[k]=1;//k被访问过//        for(j=1; j<=n; j++)//        {//            if(!vis[j]&&dis[j]>dis[k]+map[k][j])//            {//                dis[j]=dis[k]+map[k][j];//            }//        }////    }//    return ;//}

0 0
原创粉丝点击