最短路——迪杰斯特拉算法 HDU_3790

初识最短路,今天只弄了一个迪杰斯特拉算法,而且还没弄成熟,只会最基本的O(n^2),想弄个优先队列都发现尼玛被坑爆了,那个不应该用迪杰斯特拉算法写

表示还是不会优化版的迪杰斯特拉算法,(使用优先队列),只会普通的O(n^2);

用HDU_3790来详解这个算法吧。

 

最短路径问题
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit Status

Description

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
 

Input

输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
 

Output

输出 一行有两个数, 最短距离及其花费。
 

Sample Input

3 2 1 2 5 6 2 3 4 5 1 3 0 0
 

Sample Output

9 11

在迪杰斯特拉算法里,除了必要的建图和初始化,核心部分其实很简单。。。而且理解了搜索路径的过程,更加方便。

初始化部分

d[]数组存放当前节点到源点的最短路径,除了d[源点]=0,其余全部设置为INF

v[i][j]数组存放从i到j的路程,在读入数据之前,全部设置为INF

vis[]数组用来存放已经得到最短路径的点,用该数组的目的是为了防止该点被再次搜索。

吃完饭之后忽然想到,有一点很重要没有提醒。。。在无向图里面,读入边权值时,需要v[i][j]=v[j][i]=权值,原因很简单,无向图。

核心部分

 直接贴代码讲算了

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1<<30
int d[1005][1005];
int fee[1005][1005];
int distant[1005];
int p[1005];
int vis[1005];
int n,m;
void dijst(int be,int en)//迪杰斯特拉算法的核心部分。
{
    memset(vis,0,sizeof vis);//初始化vis数组
    int i,j,k;
    for (i=1; i<=n; i++)//初始化每个节点的最短路程和费用,在搜索前,默认都为INF
    {
        distant[i]=maxn;
        p[i]=maxn;
    }
    distant[be]=0;//源点的最短路径设置为0
    p[be]=0;
    for (i=1; i<=n; i++)//遍历所有节点
    {
        int min=maxn,minloc=0,minip=maxn;
        for (j=1; j<=n; j++)  //找出当前还没vis过的节点中的最短路径点(第一次肯定是源点)。。由于这道题涉及费用比较,所以写得长了一些。
        {
            if (vis[j]) continue;
            if (distant[j]<min)
            {
                min=distant[j];
                minloc=j;
                minip=p[j];
            }
            if (distant[j]==min&&min<maxn)
            {
                minloc= minip<=p[j]?minloc:j;
                min=distant[minloc];
                minip=p[minloc];
            }
        }
        vis[minloc]=1; //循环过后,minloc点必定是路径最小点,vis它一下。
        for (k=1; k<=n; k++)
        {
            if (vis[k]) continue;
            if (d[k][minloc]==maxn) continue;
            if (distant[k]>distant[minloc]+d[k][minloc]) //将上面找到的“源点”依次与所有点遍历一遍,这样基于该源点往下走的所有节点的“当前最短路”全部求出来了,当然没有路劲链接的点 长度为INF,所以不会改变,也不影响结果。
            {
                distant[k]=distant[minloc]+d[k][minloc];
                p[k]=p[minloc]+fee[minloc][k];
            }
            if (distant[k]==distant[minloc]+d[k][minloc])
            {
                if (p[k]>p[minloc]+fee[minloc][k])
                    p[k]=p[minloc]+fee[minloc][k];
            }
        }
    }
}

int main()
{

    while (scanf("%d %d",&n,&m)&&n)
    {
        int i,j,k;
        for (i=1; i<=n; i++)
        {
            for (j=1; j<=n; j++)//初始化距离和费用
            {
                d[i][j]=maxn;
                fee[i][j]=maxn;
            }
        }
        for (i=0; i<m; i++)
        {
            int a,b,c,e;
            scanf("%d %d %d %d",&a,&b,&c,&e);
            if (d[a][b]>c)  //基于这个题目,这里的判断是必须的,因为根据题意,a到b可能有好几条路,而且路程允许相等,这个时候就要比较费用大小了
            {
                d[a][b]=d[b][a]=c;
                fee[a][b]=fee[b][a]=e;//无向图,所以要a到b b到a都设置一下
            }
            if (d[a][b]==c&&fee[b][a]>e)
            {
                fee[b][a]=fee[a][b]=e;
            }
        }
        int sta,end;
        scanf("%d %d",&sta,&end);
        dijst(sta,end);
        printf("%d %d\n",distant[end],p[end]);//源点到任意点end的最短路径就保存在distant[]数组中,调用即可。
    }
    return 0;
}

 

posted @ 2013-08-06 23:33  KRisen  阅读(400)  评论(0)    收藏  举报