题目1447:最短路

// 弗洛伊德算法:求两点间的最短路径 

// 特点:时间复杂度为O(n^3),结点不超过200;当两个结点间多出一条边时,选择长度较小的那条边;

 // 全源最短路径问题:多个结点对之间的最短路径问题

#include<stdio.h>
int ans[101][101];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0 && m==0) break;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                ans[i][j]=-1;          // 对邻接矩阵初始化,-1表示无穷 
            }    
            ans[i][i]=0;               // 自己到自己的路径长度为0 
        }    
        while(m--){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            ans[a][b]=ans[b][a]=c;     // 无向图 
        }
        
        for(int k=1;k<=n;k++){         // 依次代表经过的中间结点 
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    if(ans[i][k]==-1 || ans[k][j]==-1) continue;
                    // 若两值有一个为无穷,则不能经过k结点 
                    if(ans[i][j]==-1 || ans[i][j]>ans[i][k]+ans[k][j])
                        ans[i][j]=ans[i][k]+ans[k][j];    
                }
            }    
        }
        printf("%d\n",ans[1][n]);
    }
    return 0;    

}



// 迪杰斯特拉算法:求得某特定结点到其他所有结点的最短路径长度

// 特点:时间复杂度为O(n^2),空间复杂度为O(n)
// 单源最短路径问题 

#include<stdio.h> 
#include<vector>
using namespace std;
struct E{          // 邻接链表中的链表元素结构体
    int next;      // 代表直接相邻的结点
    int c;         // 代表该边的权值 
};
vector<E> edge[101];   // 邻接链表
bool mark[101];        // 标记,当mark[i]为true时表示结点i的最短路径长度已经得到,该结点已经加入集合k
int Dis[101];          // 距离向量,当mark[i]为true时,表示已得的最短路径长度;
                       // 否则,表示所有从结点1出发,经过已知的最短路径到达集合k中的某结点,
                       // 再经过一条边到达节点i的路径最短的距离 
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0 && m==0) break;
        for(int i=1;i<=n;i++)   edge[i].clear();     // 初始化邻接链表
        while(m--){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            E tmp;
            tmp.c=c;
            tmp.next=b;  edge[a].push_back(tmp);    // 将邻接信息加入邻接链表,
            tmp.next=a;  edge[b].push_back(tmp);    // 由于原图为无向图,故每条边信息都要添加到其两个顶点的两条单链表中    
        }
        for(int i=1;i<=n;i++){    // 初始化 
            Dis[i]=-1;            // 所有距离为-1,即不可达 
            mark[i]=false;        // 所有结点不属于集合k  
        } 
        Dis[1]=0;                 // 得到最近的点为结点1,长度为0
        mark[1]=true;             // 将结点1加入集合k
        int newP=1;               // 集合k中新加入的点为结点1
        for(int i=1;i<n;i++){    // 循环n-1次,按照最短路径递增的顺序确定其他n-1个点的最短路径长度 
            for(int j=0;j<edge[newP].size();j++){ // 遍历与新加入集合k中的结点直接相邻的边
                int t=edge[newP][j].next;   // 该边的另一个结点
                int c=edge[newP][j].c;      // 该边的长度
                if(mark[t]==true)  continue;       // 若另一个结点也属于集合k,则跳过
                if(Dis[t]==-1 || Dis[t]>Dis[newP]+c)  //若该结点尚不可达,或者该结点从新结点经过一条边到达时比以往距离更短
                    Dis[t]=Dis[newP]+c;               // 更新其距离信息 
            }    
            int min=123123123; // 最小值初始化为一个大整数,为找最小值做准备
            for(int j=1;j<=n;j++){         // 遍历所有结点 
                if(mark[j]==true)  continue;      // 若其属于集合k则跳过
                if(Dis[j]==-1)     continue;      // 若该结点仍不可达则跳过
                if(Dis[j]<min){                   // 若该结点经由结点1至集合k中的某点在经过一条边到达时距离小于当前最小值 
                    min=Dis[j];          // 更新其为最小值
                    newP=j;              // 新加入的点暂定为该结点 
                } 
            }
            mark[newP]=true;       // 将新加入的点加入集合k,Dis[newP]虽然数值不变,但意义发生变化,
                                   // 有所有经过集合k中的结点再经过一条边时的距离中的最小值变为从结点1到结点newP的最短距离 
        } 
        printf("%d\n",Dis[n]);
    }
    return 0;    
}                       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值