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; } } }
注释:先求最早发生事件,再求最晚发生事件,最后根据前面两个求出每个活动的最早发生时间和最晚发生时间,然后活动这两个时间相同的就是关键路径。
第13周实验数据结构
最新推荐文章于 2022-11-16 18:05:18 发布