链式前向星和优先队列实现有向图/无向图的最短路(解题日志)
先看例题:poj3268银牛节
题目大意:各个农场派一只奶牛去指定农场参加银牛节,计算在选择最优路径时耗费最多时间。
题目解析:由于m为10^5本题用普通的邻接列表必然超时,因此学习新的方法链式前向星,相比较前向星而言时间复杂度仅为O(m)。
算法解析:该算法是将起点相同的路径归为一类,然后每个路径节点的next指向上一节点,第一个节点则指向-1。
样例实现最终图示(以x为起点):
诶嘿(*・ω< ) 。
添加路径代码:
void add(int u,int v,int w){
edage1[cnt].to=v;
edage1[cnt].next=head1[u];
edage1[cnt].w=w;
head1[u]=cnt;
}
单起点遍历代码:
for(int i=head1[v];i!=-1;i=edage1[i].next){
int temp=edage1[i].to;
if(dis1[temp]>dis1[v]+edage1[i].w){
dis1[temp]=dis1[v]+edage1[i].w;
q.push(P(dis1[temp],temp));
}
}
如果是无向图的话这样就足够了(把路径交换添加),但是此题是有向图,当然有向图也很简单,分开来就行了,需要两张图来存储。
实现代码:
void add(int u,int v,int w){
edage1[cnt].to=v;
edage1[cnt].next=head1[u];
edage1[cnt].w=w;
head1[u]=cnt;
edage2[cnt].to=u;
edage2[cnt].next=head2[v];
edage2[cnt].w=w;
head2[v]=cnt;
cnt++;
}
然后就是优先队列的优化,作用就是省去每次查找最短路的时间
最后给出完整代码:
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1009;
const int maxe=100000;
typedef int long long ll;
typedef pair <int,int> P;
int head1[maxn],head2[maxn];
struct node{
int to;
int next;
int w;
}edage1[maxe],edage2[maxe];
int cnt;
int dis1[maxn],dis2[maxn];
void init(){
cnt=0;
memset(dis1,inf,sizeof dis1);
memset(dis2,inf,sizeof dis2);
memset(head1,-1,sizeof head1);
memset(head2,-1,sizeof head2);
}
void add(int u,int v,int w){
edage1[cnt].to=v;
edage1[cnt].next=head1[u];
edage1[cnt].w=w;
head1[u]=cnt;
edage2[cnt].to=u;
edage2[cnt].next=head2[v];
edage2[cnt].w=w;
head2[v]=cnt;
cnt++;
}
void djk1(int start){
priority_queue<P,vector<P>,greater<P>>q;
dis1[start]=0;
q.push(P(0,start));
while(!q.empty()){
P p=q.top();q.pop();
int v=p.second;
if(dis1[v]<p.first)continue;
for(int i=head1[v];i!=-1;i=edage1[i].next){
int temp=edage1[i].to;
if(dis1[temp]>dis1[v]+edage1[i].w){
dis1[temp]=dis1[v]+edage1[i].w;
q.push(P(dis1[temp],temp));
}
}
}
return;
}
void djk2(int start){
priority_queue<P,vector<P>,greater<P>>q;
dis2[start]=0;
q.push(P(0,start));
while(!q.empty()){
P p=q.top();q.pop();
int v=p.second;
if(dis2[v]<p.first)continue;
for(int i=head2[v];i!=-1;i=edage2[i].next){
int temp=edage2[i].to;
if(dis2[temp]>dis2[v]+edage2[i].w){
dis2[temp]=dis2[v]+edage2[i].w;
q.push(P(dis2[temp],temp));
}
}
}
return;
}
int main(){
int n,m,x;
cin>>n>>m>>x;
init();
for(int i=0;i<m;++i){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
djk1(x);djk2(x);
int ans=0;
for(int i=1;i<=n;++i){
if(dis1[i]!=inf&&dis2[i]!=inf)
ans=max(ans,dis1[i]+dis2[i]);
}
cout<<ans<<endl;
return 0;
}
完了。