优化思路:将原队列改成双端队列,对要加入队列的点 p,如果 dist[p] 小于队头元素 u 的 dist[u],将其插入到队头,否则插入到队尾。
//SLF优化 void spfa_slf(int s,int t,GH *G)//起点s,终点t,图G { //节点编号从0开始 int n=G->vexnum;//节点个数 int *dist=new int[n];//距离数组 bool *visit=new bool[n];//访问标记数组 int *pre=new int[n];;//前驱 AR *p; //初始化 memset(dist,0x3f,n*sizeof(int)); memset(visit,0,n*sizeof(bool)); memset(pre,-1,n*sizeof(int)); deque<int>Q;//建立双端队列,并将起点入队 visit[s]=1; dist[s]=0; Q.push_back(s); //进行操作 while (!Q.empty()) { int cur=Q.front(); Q.pop_front(); visit[cur]=0;//出队节点取消标记 p=G->N[cur].next; while (p)//遍历出队节点的直接后继 { if (dist[p->index] > dist[cur] + (p->weight))//需要进行松弛操作 { dist[p->index]=dist[cur] + (p->weight); pre[p->index]=cur; if (!visit[p->index]) { visit[p->index]=1; if(!Q.empty() && dist[p->index] < dist[Q.front()])//根据dist[p->index]与dist[Q.front()]的大小关系,决定p->index插入到队头还是队尾 Q.push_front(p->index); else Q.push_back(p->index); } } p=p->next; } } if (dist[t] == INF) cout<<"两点不连通."<<endl; else//输出最短路径 { cout<<"存在长度为"<<dist[t]<<"的最短路径:"<<endl; int *path=new int[n];//存放路径 int top=-1; int q=t; while (q != -1)//将前驱入栈 { top++; path[top]=q; q=pre[q]; } for (; top > 0; top--) cout<<G->vexname[path[top]]<<"-->"; cout<<G->vexname[path[0]]<<endl; delete []path; } delete []dist; delete []visit; delete []pre; }优化思路:对每个要出队的队头元素 u,比较 dist[u] 和队列中点的 dist 的平均值,如果 dist[u] 更大,将其弹出放到队尾,然后取队首元素进行相同操作,直到队头元素的 dist 小于等于平均值。
//LLL优化 void spfa_lll(int s,int t,GH *G)//起点s,终点t,图G { //节点编号从0开始 int n=G->vexnum;//节点个数 int *dist=new int[n];//距离数组 bool *visit=new bool[n];//访问标记数组 int *pre=new int[n];//前驱数组 int num;//队列中点的个数 int sum;//队列中点的dist之和 AR *p; //初始化 memset(dist,0x3f,n*sizeof(int)); memset(visit,0,n*sizeof(bool)); memset(pre,-1,n*sizeof(int)); queue<int>Q;//建立队列,并将起点入队 visit[s]=1; dist[s]=0; Q.push(s); num=1; sum=dist[s]; while (!Q.empty()) { int cur = Q.front(); //LLL优化 while (num*dist[cur] > sum)//表示队首元素的dist高于平均值,将其放到队尾 { Q.pop(); Q.push(cur); cur = Q.front(); } Q.pop(); visit[cur] = 0;//出队,并取消标记 num--; sum -= dist[cur]; p=G->N[cur].next; while (p) { if (dist[p->index] > dist[cur] + (p->weight))//需要进行松弛操作 { dist[p->index]=dist[cur] + (p->weight); pre[p->index]=cur; if (!visit[p->index]) { visit[p->index]=1; Q.push(p->index);//直接入队 num++;//更新相关参数 sum+=dist[p->index]; } } p=p->next; } } if (dist[t] == INF) cout<<"两点不连通."<<endl; else//输出最短路径 { cout<<"存在长度为"<<dist[t]<<"的最短路径:"<<endl; int *path=new int[n];//存放路径 int top=-1; int q=t; while (q != -1)//将前驱入栈 { top++; path[top]=q; q=pre[q]; } for (; top > 0; top--) cout<<G->vexname[path[top]]<<"-->"; cout<<G->vexname[path[0]]<<endl; delete []path; } delete []dist; delete []visit; delete []pre; }这两种优化方法并不相互干扰,故可同时使用,下附代码。
//SLF+LLL优化 void spfa_slf_lll(int s, int t, GH *G)//起点s,终点t,图G { //节点编号从0开始 int n=G->vexnum;//节点个数 int *dist=new int[n];//距离数组 bool *visit=new bool[n];//访问标记数组 int *pre=new int[n];//前驱数组 int num;//队列中点的个数 int sum;//队列中点的dist之和 AR *p; //初始化 memset(dist,0x3f,n*sizeof(int)); memset(visit,0,n*sizeof(bool)); memset(pre,-1,n*sizeof(int)); deque<int>Q;//建立双端队列,并将起点入队 visit[s]=1; dist[s]=0; Q.push_back(s); num=1; sum=dist[s]; while (!Q.empty()) { int cur=Q.front(); //LLL优化 while (num*dist[cur] > sum)//表示队首元素的dist高于平均值,将其放到队尾 { Q.pop_front(); Q.push_back(cur); cur=Q.front(); } Q.pop_front(); visit[cur]=0;//出队,并取消标记 num--; sum-=dist[cur]; //SLF优化 p=G->N[cur].next;//遍历出队节点的直接后继 while (p) { if (dist[p->index] > dist[cur] + (p->weight))//需要进行松弛操作 { dist[p->index]=dist[cur] + (p->weight); pre[p->index]=cur; if (!visit[p->index]) { visit[p->index]=1; if(!Q.empty() && dist[p->index]<dist[Q.front()])//根据dist[p->index]与dist[Q.front()]的大小关系,决定p->index插入到队头还是队尾 Q.push_front(p->index); else Q.push_back(p->index); num++;//更新相关参数 sum+=dist[p->index]; } } p=p->next; } } if (dist[t] == INF) cout<<"两点不连通."<<endl; else//输出最短路径 { cout<<"存在长度为"<<dist[t]<<"的最短路径:"<<endl; int *path=new int[n];//存放路径 int top=-1; int q=t; while (q != -1)//将前驱入栈 { top++; path[top]=q; q=pre[q]; } for (; top > 0; top--) cout<<G->vexname[path[top]]<<"-->"; cout<<G->vexname[path[0]]<<endl; delete []path; } delete []dist; delete []visit; delete []pre; }以洛谷上的题目 P3381【模板】最小费用最大流 为例比较优化结果。
1.没有进行优化的结果 2.SLF优化的结果 3.LLL优化的结果 4.SLF+LLL优化的结果