第13周实验数据结构

13.1 迪杰斯特拉最短路径(一点到其他所有点)

【输入形式】

输入的第一行包含2个正整数n和s,表示图中共有n个顶点,且源点为s。其中n不超过50,s小于n。

以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。

【输出形式】

只有一行,共有n-1个整数,表示源点至其它每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。

请注意行尾输出换行。

【样例输入】

4 1
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

【样例输出】

6 4 7

【样例说明】

在本题中,需要按照题目描述中的算法完成迪杰斯特拉算法,并在计算最短路径的过程中将每个顶点是否可达记录下来,直到求出每个可达顶点的最短路径之后,算法才能够结束。 

迪杰斯特拉算法的特点是按照路径长度递增的顺序,依次添加下一条长度最短的边,从而不断构造出相应顶点的最短路径。 

另外需要注意的是,在本题中为了更方便的表示顶点间的不可达状态,可以使用一个十分大的值作为标记。

#include <iostream>
using namespace std;
#define MAX 32765
typedef struct graph
{
    int arc[55][55];
    int vexnum;
}Gragh;
int path[50]={0};
int dist[50]={0};
bool flag[50]={0};
void Indist(Gragh gn,int s)//初始化距离数组
{
    for(int i=0;i<gn.vexnum;i++)
    {
        if(i!=s)
        {
            dist[i]=gn.arc[s][i];
        }
    }
}
int findmin(Gragh gn,int s)
{
    int min=32765;
    int k;
    for(int i=0;i<gn.vexnum;i++)
    {
        if(!flag[i]&&gn.arc[s][i]<min)
        {
            min=gn.arc[s][i];
            k=i;
        }
    }
    flag[k]=1;
    return k;
}
void DIJ(Gragh gn,int s)//求最短路径
{
    flag[s]=1;
    Indist(gn,s);
    for(int i=1;i<=gn.vexnum-1;i++)
    {
        int m=findmin(gn,s);
        for(int j=0;j<gn.vexnum;j++)
        {
            if(gn.arc[s][j]>gn.arc[s][m]+gn.arc[m][j])
            {
                gn.arc[s][j]=gn.arc[s][m]+gn.arc[m][j];
                dist[j]=gn.arc[s][j];
                path[j]=m;
            }
        }
    }
    for(int x=0;x<gn.vexnum;x++)
    {
        if(dist[x]==MAX)
            dist[x]=-1;
        if(x!=s)
        {
            cout<<dist[x]<<" ";
        }
    }
}
int main()
{
    int n,s;
    cin>>n>>s;
    Gragh gn;
    gn.vexnum=n;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cin>>gn.arc[i][j];
            if(gn.arc[i][j]==0&&i!=j)
                gn.arc[i][j]=MAX;
        }
    }
   /* cout<<n<<s<<endl;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
            cout<<gn.arc[i][j]<<" ";
        cout<<endl;
    }*/
    DIJ(gn,s);
    return 0;
}

13.2:弗洛伊德最短路径(任意两个点的最短路径)

【问题描述】

对于下面一张若干个城市,以及城市之间距离的地图,请采用弗洛伊德算法求出所有城市之间的最短路径。

【输入形式】

顶点个数n,以及n*n的邻接矩阵,其中不可达使用9999代替

【输出形式】

每两个顶点之间的最短路径和经过的顶点

注意:顶点自身到自身的dist值为0,path则为该顶点的编号

【样例输入】

4

9999 4 11 9999

6 9999 2 9999

1 9999 9999 1

9999 3 9999 9999

【样例输出】

from 0 to 0: dist = 0 path:0
from 0 to 1: dist = 4 path:0 1
from 0 to 2: dist = 6 path:0 1 2
from 0 to 3: dist = 7 path:0 1 2 3
from 1 to 0: dist = 3 path:1 2 0
from 1 to 1: dist = 0 path:1
from 1 to 2: dist = 2 path:1 2
from 1 to 3: dist = 3 path:1 2 3
from 2 to 0: dist = 1 path:2 0
from 2 to 1: dist = 4 path:2 3 1
from 2 to 2: dist = 0 path:2
from 2 to 3: dist = 1 path:2 3
from 3 to 0: dist = 6 path:3 1 2 0
from 3 to 1: dist = 3 path:3 1
from 3 to 2: dist = 5 path:3 1 2
from 3 to 3: dist = 0 path:3

#include<iostream>

using namespace std;
#define MAX 9999
typedef struct gragh
{
           int arc[55][55];
           int vexnum;
}Gragh;
int main()
{
           int path[55][55];
           int dist[55][55];
           int n;
           cin>>n;
           Gragh gn;
           gn.vexnum=n;
           for(int i=0;i<n;i++)//输入+初始化
           {
                      for(int j=0;j<n;j++)
                      {
                                 cin>>gn.arc[i][j];
                                 if(i==j)
                                            gn.arc[i][j]=0;
                                 dist[i][j]=gn.arc[i][j];
                                 if(i==j||gn.arc[i][j]==MAX)//这里题目要求i==j时路径就是它本身
                                 {
                                            path[i][j]=i;
                                 }
                                 else
                                            path[i][j]=i;
                      }
           }
           for(int k=0;k<n;k++)
                      for(int i=0;i<n;i++)
                                 for(int j=0;j<n;j++)
                                 {
                                            if(dist[i][k]+dist[k][j]<gn.arc[i][j])
                                            {
                                                       gn.arc[i][j]=dist[i][k]+dist[k][j];
                                                       dist[i][j]=gn.arc[i][j];
                                                       path[i][j]=k;
                                            }
                                 }
           for(int i=0;i<n;i++)
           {
                      for(int j=0;j<n;j++)
                      {
                                 cout<<"from "<<i<<" to "<<j<<": dist = "<<gn.arc[i][j]<<" path:";
                                 int c=j;
                                 int Path[55];
                                 Path[0]=j;
                                 int x=0;
                                 if(i==j)
                                 {
                                            cout<<i<<endl;
                                 }
                                 else
                                 {
                                             while(path[i][c]!=i)
                                 {
                                            Path[++x]=path[i][c];
                                            c=path[i][c];
                                 }
                                 Path[++x]=i;
                                 for(int y=x;x>=0;x--)
                                 {
                                            cout<<Path[x]<<" ";
                                 }
                                 cout<<endl;
                                 }
                      }
           }
          /* for(int i=0;i<n;i++)
           {
                      for(int j=0;j<n;j++)
                                 cout<<path[i][j]<<" ";
                      cout<<endl;
           }*/
}

13.3关键路径:

【问题描述】若在带权的有向图中,以顶点表示事件,以有向边表示活动,边上的权值表示活动的开销(如该活动持续的时间),则此带权的有向图称为AOE网。如果用AOE网来表示一项工程,那么,仅仅考虑各个子工程之间的优先关系还不够,更多的是关心整个工程完成的最短时间是多少;哪些活动的延期将会影响整个工程的进度,而加速这些活动是否会提高整个工程的效率。因此,通常在AOE网中列出完成预定工程计划所需要进行的活动,每个活动计划完成的时间,要发生哪些事件以及这些事件与活动之间的关系,从而可以确定该项工程是否可行,估算工程完成的时间以及确定哪些活动是影响工程进度的关键。
【输入形式】第一行输入两个数字,分别表示顶点数和边数;从第二行开始,输入边的信息,格式为(i,j, weight)
【输出形式】关键路径的总时间(最大路径长度),代表关键活动的边,格式为(顶点1,顶点2),按大小顺序排列
【样例输入】
6 8
0 1 3
0 2 2
1 3 2
1 4 3
2 3 4
2 5 3
3 5 2
4 5 1
【样例输出】

8

0 2

2 3

3 5

【问题描述】若在带权的有向图中,以顶点表示事件,以有向边表示活动,边上的权值表示活动的开销(如该活动持续的时间),则此带权的有向图称为AOE网。如果用AOE网来表示一项工程,那么,仅仅考虑各个子工程之间的优先关系还不够,更多的是关心整个工程完成的最短时间是多少;哪些活动的延期将会影响整个工程的进度,而加速这些活动是否会提高整个工程的效率。因此,通常在AOE网中列出完成预定工程计划所需要进行的活动,每个活动计划完成的时间,要发生哪些事件以及这些事件与活动之间的关系,从而可以确定该项工程是否可行,估算工程完成的时间以及确定哪些活动是影响工程进度的关键。
【输入形式】第一行输入两个数字,分别表示顶点数和边数;从第二行开始,输入边的信息,格式为(i,j, weight)
【输出形式】关键路径的总时间(最大路径长度),代表关键活动的边,格式为(顶点1,顶点2),按大小顺序排列
【样例输入】
6 8
0 1 3
0 2 2
1 3 2
1 4 3
2 3 4
2 5 3
3 5 2
4 5 1
【样例输出】

8

0 2

2 3

3 5

#include<iostream>
#include<stdlib.h>
using namespace std;
#define MAX 100
int ve[MAX]={0};
int vl[MAX]={0};
int n,m;
typedef struct arcnode
{
    int data;
    int weight;
    struct arcnode *next=NULL;
}ArcNode;
typedef struct vertexnode
{
    int  data;//顶点
    ArcNode *first=NULL;
}VertexNode;
typedef struct stack
{
    VertexNode point[99];
    int top;
}Stack;
void push(Stack &a,VertexNode point)
{
    if(a.top>=99)
        exit(0);
    else
    {
        a.top++;
        a.point[a.top]=point;
    }
}
void pop(Stack &a,VertexNode &point)
{
    if(a.top==-1)
        exit(0);
    else
    {
        point=a.point[a.top];
        a.top--;
    }
}
//算每个顶点的入度
void Jindegree(int indegree[],VertexNode List[])
{
    for(int i=0;i<n;i++)
    {
        ArcNode *p=List[i].first;
        while(p!=NULL)
        {
            indegree[p->data]++;
            p=p->next;
        }
    }
}
int main()
{
    cin>>n>>m;//顶点数和边数
    VertexNode point[n];
    for(int i=0;i<n;i++)
        point[i].data=i;
    //建立邻接表
    for(int i=0;i<m;i++)
    {
        int x,y,weight;
        cin>>x>>y>>weight;
        //cout<<1<<endl;
        ArcNode *p=NULL;
        p=new ArcNode;
        p->data=y;
        p->weight=weight;
        p->next=NULL;

        if(point[x].first==NULL)
        {
            point[x].first=p;
        }
        else
        {
            ArcNode *pp=point[x].first;
            while(pp->next!=NULL)
                pp=pp->next;
            pp->next=p;
        }
    }
    /*for(int i=0;i<n;i++)
    {
        ArcNode *q=point[i].first;
        cout<<i<<" : ";
        while(q!=NULL)
        {
            cout<<q->data<<" "<<q->weight<<endl;
            q=q->next;
        }
    }*/
    int indegree[n]={0};
    Jindegree(indegree,point);//算各点入度
    Stack a,b;//a:存入度为0的顶点。b:存入逆序且修改后的拓扑排序
    a.top=-1;b.top=-1;
    for(int i=0;i<n;i++)
    {
        if(indegree[i]==0)
            push(a,point[i]);
    }
    while(a.top!=-1)
    {
        VertexNode j;
        pop(a,j);
        push(b,j);//逆序记录拓扑排序
        ArcNode *t=j.first;
        while(t!=NULL)
        {
            int k=t->data;
            if(--indegree[k]==0)
                push(a,point[k]);
            if(ve[j.data]+t->weight>ve[k])//计算每个顶点的最早发生时间
                ve[k]=ve[j.data]+t->weight;
            t=t->next;
        }
    }
    //计算每个顶点的最晚发生时间,计算每个活动的最早和最晚发生时间
    for(int i=0;i<n;i++)
    {
        vl[i]=ve[n-1];
    }
    while(b.top!=-1)
    {
        VertexNode h;
        pop(b,h);
        ArcNode *d=h.first;
        while(d!=NULL)
        {
            int g=d->data;
            if(vl[g]-d->weight<vl[h.data])
                vl[h.data]=vl[g]-d->weight;
            d=d->next;
        }
    }
    cout<<ve[n-1]<<endl;
    for(int i=0;i<n;i++)
    {
        ArcNode *f=point[i].first;
        int ei,li;
        while(f!=NULL)
        {
            ei=ve[i];
            li=vl[f->data]-f->weight;
            if(ei==li)
            cout<<i<<" "<<f->data<<endl;
            f=f->next;
        }
    }
}

注释:先求最早发生事件,再求最晚发生事件,最后根据前面两个求出每个活动的最早发生时间和最晚发生时间,然后活动这两个时间相同的就是关键路径。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值