7-2 公路村村通 迪杰斯特拉(dijkstra)算法

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

同笔者其他文章一样,

在完成这道题之前, 首先要对构迪杰斯特拉算法的框架有一定的理解。

之后再根据题目的要求进行恰当的修改。

框架代码: 

#include <iostream>
#include <stdlib.h>
#include <queue>
using namespace std;

#define INFINITY 32767

typedef struct
{
    int *vexs;   //顶点表
    int **arc;  //邻接矩阵,可看作边表
    int numVertexes,numEdges;  //图中当前的顶点数和边数
}MGraph;

MGraph* InitGraph(int numVer,int numEdge)
{
    MGraph *G;
    G = (MGraph*)malloc(sizeof(MGraph));
    G->vexs = (int*)malloc(sizeof(int)*numVer);
    G->arc = (int**)malloc(sizeof(int*)*numVer);

    for(int i=0;i<numVer;i++)
    {
    	G->vexs[i]=i;
        G->arc[i] = (int*)malloc(sizeof(int)*numVer);
        for(int j=0;j<numVer;j++)
        {
            if(i==j)
                G->arc[i][j] = 0;
            else G->arc[i][j] = INFINITY;
        }
    }
    G->numVertexes = numVer;
    G->numEdges = numEdge;

    return G;
}

int GetMin(MGraph *G,int *s,int *d)
{
    int min=INFINITY;
    int index;
    for(int i=0;i<G->numVertexes;i++)
    {
        if(s[i]==0 && d[i]<min)
        {
            min = d[i];
            index = i;
        }
    }

    return index;
}

void Dijkstra(MGraph *G,int index)
{
    int *s = (int*)malloc(sizeof(int)*G->numVertexes);
    int *p = (int*)malloc(sizeof(int)*G->numVertexes);
    int *d = (int*)malloc(sizeof(int)*G->numVertexes);


    for(int i=0;i<G->numVertexes;i++)  //初始化辅助数组
    {
        if(G->arc[index][i]>0 && G->arc[index][i]!=INFINITY)
        {
            p[i] = index;
            d[i] = G->arc[index][i];
        }    
        else 
        {
            p[i] = -1;
            d[i] = INFINITY;
        }

        if(i==index)
        {
            s[i]=1;
            d[i]=0;
        }
        else
            s[i]=0;
    }

    for(int i=0;i<G->numVertexes;i++)
    {
        int index = GetMin(G,s,d);
        s[index] = 1;
        for(int j=0;j<G->numVertexes;j++)
        {
            if(s[j]==0 && d[index] + G->arc[index][j] < d[j])
            {
                d[j] = d[index] + G->arc[index][j];
                p[j] = index;
            }
        }
    }

}

int main()
{
    MGraph *G;
    int N,M;
    cin>>N>>M;


    G = InitGraph(N,M);
    
    for(int i=0;i<M;i++)
    {
        int x,y,weight;
        cin>>x>>y>>weight;
        G->arc[x-1][y-1] = weight;
    }

    Dijkstra(G,0);

    return 0;
}

Dijsktra()函数中3个辅助数组:

  • S数组:记录了目标顶点到其他顶点的最短路径是否求得(1表示已求得,0表示为求得)
  • P数组:记录了目标顶点到其他顶点的最短路径的前驱节点(-1表示无前驱,否则为编号)
  • D数组:记录了目标顶点到其他顶点的最短路径的长度

 附上本题完整代码:

#include <iostream>
#include <stdlib.h>
#include <queue>
using namespace std;

#define INFINITY 32767

typedef struct
{
    int *vexs;   //顶点表
    int **arc;  //邻接矩阵,可看作边表
    int numVertexes,numEdges;  //图中当前的顶点数和边数
}MGraph;

MGraph* InitGraph(int numVer,int numEdge)
{
    MGraph *G;
    G = (MGraph*)malloc(sizeof(MGraph));
    G->vexs = (int*)malloc(sizeof(int)*numVer);
    G->arc = (int**)malloc(sizeof(int*)*numVer);

    for(int i=0;i<numVer;i++)
    {
    	G->vexs[i]=i;
        G->arc[i] = (int*)malloc(sizeof(int)*numVer);
        for(int j=0;j<numVer;j++)
        {
            if(i==j)
                G->arc[i][j] = 0;
            else G->arc[i][j] = INFINITY;
        }
    }
    G->numVertexes = numVer;
    G->numEdges = numEdge;

    return G;
}

int GetMin(MGraph *G,int *s,int *d)
{
    int min=INFINITY;
    int index;
    for(int i=0;i<G->numVertexes;i++)
    {
        if(s[i]==0 && d[i]<min)
        {
            min = d[i];
            index = i;
        }
    }

    return index;
}

int* Dijkstra(MGraph *G,int index,int end)
{
    int *s = (int*)malloc(sizeof(int)*G->numVertexes);
    int *p = (int*)malloc(sizeof(int)*G->numVertexes);
    int *d = (int*)malloc(sizeof(int)*G->numVertexes);


    for(int i=0;i<G->numVertexes;i++)  //初始化辅助数组
    {
        if(G->arc[index][i]>0 && G->arc[index][i]!=INFINITY)
        {
            p[i] = index;
            d[i] = G->arc[index][i];
        }    
        else 
        {
            p[i] = -1;
            d[i] = INFINITY;
        }

        if(i==index)
        {
            s[i]=1;
            d[i]=0;
        }
        else
            s[i]=0;
    }

    for(int i=0;i<G->numVertexes;i++)
    {
        int index = GetMin(G,s,d);
        s[index] = 1;
        for(int j=0;j<G->numVertexes;j++)
        {
            if(s[j]==0 && d[index] + G->arc[index][j] < d[j])
            {
                d[j] = d[index] + G->arc[index][j];
                p[j] = index;
            }
        }
    }

    int *road;
    road  = (int*)malloc(sizeof(int)*30);
    int i=end,cnt=2;
    while(i!=-1)  //用p数组找路径
    {
        road[cnt]=i;
        i=p[i];
        cnt++;
    }

    road[1]=d[end];  //数组road[1]存最短路径
    road[0]=cnt-1;   //数组road[0]存总的路径数
    //这样便于在主函数中对边time和length的路径是否相同
    //也就是真正的路径是从2开始,从cnt倒叙开始,cnt个数

    return road;


 
}

int main()
{
    MGraph *G_length;
    MGraph *G_time;
    int N,M;
    cin>>N>>M;


    G_length = InitGraph(N,M);
    G_time = InitGraph(N,M);
    
    for(int i=0;i<M;i++)
    {
        int x,y,way,length,time;
        cin>>x>>y>>way>>length>>time;
        if(way==1)
        {
            G_length->arc[x][y] = length;
            G_time->arc[x][y] = time;
        }else{
            G_length->arc[x][y] = length;
            G_length->arc[y][x] = length;
            G_time->arc[x][y] = time;
            G_time->arc[y][x] = time;
        }
    }

    int start,end;
    cin>>start>>end;


    int *road_length,*road_time;
    //cout<<endl<<"Time = ";
    road_time = Dijkstra(G_time,start,end);
    
    //cout<<endl<<"Distance = ";
    road_length = Dijkstra(G_length,start,end);

    //总之运行完算法,返回,想办法满足题目要求的输出即可。

    int flag = 0; //0表示两条路线不一样,1表示两条路线一样
    if(road_length[0] == road_time[0])
    {
        int j;
        for(j=2;j<road_length[0]+2;j++)
        {
            if(road_length[j]!=road_time[j])
                break;
        }

        if(j==road_length[0]+2)
            flag=1;
    }

    if(flag==1)
    {
        printf("Time = %d; Distance = %d:",road_time[1],road_length[1]);
        for(int j=road_time[0];j>=2;j--)
        {
        if(j!=2)
            printf(" %d =>",road_time[j]);
        else printf(" %d",road_time[j]);
        }
    }else{
        cout<<endl<<"Time = "<<road_time[1]<<":";
        for(int j=road_time[0];j>=2;j--)
        {
        if(j!=2)
            printf(" %d =>",road_time[j]);
        else printf(" %d",road_time[j]);
        }
        cout<<endl<<"Distance = "<<road_length[1]<<":";
        for(int j=road_length[0];j>=2;j--)
        {
        if(j!=2)
            printf(" %d =>",road_length[j]);
        else printf(" %d",road_length[j]);
        }
    }
  


    return 0;
}


总结:

        主要学习迪杰斯特拉算法的写法。针对于本题,就是对迪杰斯特拉算法的应用。为满足题目要求,本代码虽能够实现,但是逻辑较差,阅读代码稍微较困难。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亮子i_12138

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值