图--有向无负权回路的单源最短路径 DAG 算法导论p365

来源:互联网 发布:天猫美工外包价格 编辑:程序博客网 时间:2024/06/06 08:33

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的前驱uDFS_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;}