HDU 1385 Minimum Transport Cost (floyd算法,求最短路径)

http://acm.hdu.edu.cn/showproblem.php?pid=1385

这个是模板题目。

核心算法:

通过一个图的权值矩阵求出它的每两点间的最短路径矩阵
从图的带权邻接矩阵A=[a(i,j)] n×n开始,递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1);又用同样地公式由D(1)构造出D(2);……;最后又用同样的公式由D(n-1)构造出矩阵D(n)。矩阵D(n)的i行j列元素便是i号顶点到j号顶点的最短路径长度,称D(n)为图的距离矩阵,同时还可引入一个后继节点矩阵path来记录两点间的最短路径。
采用的是(松弛技术),对在i和j之间的所有其他点进行一次松弛。所以时间复杂度为O(n^3);
其状态转移方程如下: map[i,j]:=min{map[i,k]+map[k,j],map[i,j]}
map[i,j]表示i到j的最短距离
K是穷举i,j的断点
map[n,n]初值应该为0,或者按照题目意思来做。
当然,如果这条路没有通的话,还必须特殊处理,比如没有map[i,k]这条路
算法
1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
===
把图用邻接距阵G表示出来,如果从Vi到Vj有路可达,则G[i,j]=d,d表示该路的长度;否则G[i,j]=无穷大。
定义一个距阵D用来记录所插入点的信息,D[i,j]表示从Vi到Vj需要经过的点,初始化D[i,j]=j。
把各个顶点插入图中,比较插点后的距离与原来的距离,G[i,j] = min( G[i,j], G[i,k]+G[k,j] ),如果G[i,j]的值变小,则D[i,j]=k。
在G中包含有两点之间最短道路的信息,而在D中则包含了最短通路径的信息。
算法易于理解及书写,但是时间复杂度太高。
#include<stdio.h>
#include<string.h>
#define MAX 9999999
int ans[1000][1000],map[1000][1000],tax[1000];
int vertex;
int min(int a,int b)
{
    return a<b?a:b;
}
void init()
{
    int i,j;
    for(i=0;i<vertex;i++)
        for(j=0;j<vertex;j++)
        if(i==j)map[i][j]=0;
        else map[i][j]=MAX;//起点跟终点一致,说明可以0费用,否则就先初始化为最大
}
void input()
{
    int i,x,y,cost,j;
    for(i=0;i<vertex;i++)
        for(j=0;j<vertex;++j)
        {
            scanf("%d",&cost);
            if(cost!=-1)
                map[i][j]=cost;
            ans[i][j]=j;
        }
    for(i=0;i<vertex;++i)
        scanf("%d",&tax[i]);
}
int floyd()
{
    int i,j,k,sum;
    for(k=0;k<vertex;++k)
        for(i=0;i<vertex;++i)
            for(j=0;j<vertex;++j)
            {
                sum=map[i][k]+map[k][j]+tax[k];
                if(sum<map[i][j])
                {
                    map[i][j]=sum;//如果存在k点使得ij路径可松弛,那么就更新这条路径上的数据
                    ans[i][j]=ans[i][k];//存储该点的前一点
                }
                else if(sum==map[i][j])//这里是为了字典序
                {
                    ans[i][j]=min(ans[i][j],ans[i][k]);

                }
            }
}
void print(int start,int end)
{
    int k,i;
    printf("From %d to %d :\n",start+1,end+1);
    printf("Path: %d",start+1);
    k=start;
    while(k!=end)//输出路径从起点到终点
    {
        printf("-->%d",ans[k][end]+1);
        k=ans[k][end];
    }
    printf("\n");
    printf("Total cost : %d\n\n",map[start][end]);
}

int main()
{
    int i,j,start,end;
    while(scanf("%d",&vertex),vertex)
    {
        init();
        input();
        floyd();
        while(scanf("%d%d",&start,&end),start!=-1||end!=-1)
        print(start-1,end-1);//这里一定记得要把点跟下标对齐,即-1
    }
    return 0;
}
View Code

 

posted @ 2013-08-27 20:17  执着追求的IT小小鸟  阅读(202)  评论(0编辑  收藏  举报