DAG_SHORTEST_PATHS该算法是对某加权的有向无回路图(即DAG图),特指的是无负权回路图,即可是带负权边的图或是带正值的回路图。时间是(V+E)
实现步骤是:
1、建立有向邻接表
2、然后DAG_SHORTEST_PATHS函数:该函数主要是对图dag
1、进行拓扑排序(即是1、对图进行深搜 2、按深搜完成时间有大到小排列 (这是利用point向量对 图进行排序,所以各点在AdjList向量中的位置不变)
2、然后按拓扑排序的顺序只对各边松弛一次就即可
3、输出
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 99999999//表示无穷大
typedef struct node
{
int adjvex;//连接点
int weight;//边的权值
struct node *next;
}EdgeNode;
typedef struct vnode
{
char str[20];
int pre;//该点深搜时的前驱
int dis;//节点发现时间
int fish;//记录该顶点完成时间即该点标为黑色的时间
int color;//1代表白色表示该点尚未发现 2代表灰色现已发现 3代表黑色表示与它邻接的边已发现
int distance;//源点到该的距离
EdgeNode *firstedge;
}VertexNode;
VertexNode AdjList[10001];
typedef struct
{
int fish;//完成时间
int id;// 指示拓扑排序后 AdjList向量中分量的位置
}dpoint;
dpoint point[10001];
int time;//时间计数器
void CREAT_ADJLIST_GRAPH(int n,int e) //节点及边的录入 以及建立邻接表
{
int i,j,s,d,find,weight;
char str1[20],str2[20];
EdgeNode *p;
printf("请输入一次输入所有字符节点 且第一个输入的点默认为源节点\n");
for(i=0;i<n;i++)
{
scanf("%s ",&AdjList[i].str);
AdjList[i].firstedge=NULL;
}
printf("请输入各条边\n");
for(i=1;i<=e;i++)//建立邻接表 由于是无向图则要申请两个节点p和q
{
find=0;
scanf("%s %s %d",&str1,&str2,&weight);// u ->v &权值
for(j=0;find!=2&&j<n;j++)
if(strcmp(str1,AdjList[j].str)==0)
{
s=j;
find++;
}
else if(strcmp(str2,AdjList[j].str)==0)
{
d=j;
find++;
}
p=(EdgeNode*)malloc(sizeof(EdgeNode));
p->adjvex=d;
p->weight=weight;
p->next=AdjList[s].firstedge;
AdjList[s].firstedge=p;
}
}
void DFS_VISIT(int u)//深度搜索递归函数
{
int v;
EdgeNode *p;
AdjList[u].color=2;//u节点已发现 标记为灰色
time++;
AdjList[u].dis=time;
p=AdjList[u].firstedge;
while(p)
{
v=p->adjvex;
if(AdjList[v].color==1)
{
AdjList[v].pre=u; //记录v的前驱u
DFS_VISIT(v);//递归深搜
}
p=p->next;
}
AdjList[u].color=3;//u节点所有邻接点均已发现,即完成任务,标记为黑色
AdjList[u].fish=time=time+1;//标记完成时间
}
void DFS(int n)//深度搜索
{
int i;
for(i=0;i<n;i++)
{
AdjList[i].color=1;//1代表白色表示该点尚未发现
AdjList[i].pre=-1;//前驱向量初始化
}
time=0;
for(i=0;i<n;i++)
if(AdjList[i].color==1)
DFS_VISIT(i);
}
int cmp(const void *a,const void *b)
{
return( ((dpoint*)b)->fish-((dpoint*)a)->fish );//从大到小排列
}
void TOPOLOGICAL_SORT(int n)//拓扑排序(其实是对point向量来拓扑排序)
{
int i;
DFS(n);//对顶点进行深度搜索
for(i=0;i<n;i++)
{
point[i].fish=AdjList[i].fish;
point[i].id=i;
}
qsort(point,n,sizeof(point[0]),cmp);//时间按完成时间由大到小排序
}
void printpath(int i)//路径输出
{
if(AdjList[i].pre==-1)
{
printf("%s->",AdjList[i].str);
return ;
}
else
{
printpath(AdjList[i].pre);
printf("-%s",AdjList[i].str);
}
}
void print(int n)//输出
{
int i;
//for(i=0;i<n;i++)//排序输出
// printf("%7s %d",AdjList[i].str,AdjList[i].distance);
// printf("\n");
for(i=0;i<n;i++)
if(AdjList[i].pre!=-1)
{
printf("%d: ",AdjList[i].distance);
printpath(i);
printf("\n");
}
else if(i==0)
printf("%d: %s\n",AdjList[i].distance,AdjList[i].str);
else
printf(" 无穷大 %s\n",AdjList[i].str);
printf("\n");
}
void INITIALIZE_SINGLE_SOURCE(int n)//
{
int i;
for(i=0;i<n;i++)
{
AdjList[i].pre=-1;
AdjList[i].distance=MAX;
}
AdjList[0].distance=0;//源点 的距离初始化为0;
}
void RELAX(int u,int v,int weight)//松弛技术
{
if(AdjList[v].distance>AdjList[u].distance+weight)
{
AdjList[v].distance=AdjList[u].distance+weight;
AdjList[v].pre=u;
}
}
void DAG_SHORTEST_PATHS(int n)
{
int u,v,weight,i;
EdgeNode *p;
TOPOLOGICAL_SORT(n);//拓扑排序
INITIALIZE_SINGLE_SOURCE(n);
for(i=0;i<n;i++)//按完成时间由大到小依次对每条边进行松弛
{
u=point[i].id;//u 指示(的是拓扑中完成时间较晚的量)在AdjList向量中的位置
p=AdjList[u].firstedge;
while(p)
{
v=p->adjvex;
weight=p->weight;
RELAX(u,v,weight);//进行松弛
p=p->next;
}
}
print(n);//输出
}
int main()
{
freopen("1.txt","r",stdin);
int n,e;
printf("请输入字符节点的个数N 和边的数目E:\n");
scanf("%d%d ",&n,&e);
CREAT_ADJLIST_GRAPH(n,e); //节点及边的录入 以及建立邻接表
DAG_SHORTEST_PATHS(n); //求DAG图单源最短路径
return 0;
}
本文介绍了一种针对有向无环图(DAG)的最短路径算法,该算法能够高效地找出图中从源点到其他各点的最短路径。通过拓扑排序和仅对各边进行一次松弛操作,算法确保了计算复杂度为O(V+E)。
127

被折叠的 条评论
为什么被折叠?



