在家的这几天效率还是蛮低的,总是有其他的事情耽搁,然后最近就在做搜索题,然后做了两个搜索关于最短路径的,点数少的时候之前学的佛洛依德还能派上点用处,可以点数过1000之后就容易超时了,然后看他们的题解,都用到了一个SPFA算法
SPFA算法是用来求某个点到别的点的距离的最短/最长路径的
算法的整体思路就是使用队列不断地更新点的最短路径知道无法更新为止(感觉和BFS差不多,感觉区别就是进队的数据还是可以继续进队的)
不解释了,直接上代码吧(感觉解释不太明白hhh)
a[i][j]:邻接矩阵,记录邻接点
w[i][j]:权值矩阵,记录边的权值
d[i]:最短路径,记录从开始点到第i个点的最短路径
pre[v] 记录前趋点
exist[i]记录是否能够再一次访问
int head=0,tail=1;
q[1]=s;//s为开始点
exist[s]=true;
while(head!=tail)
{
u=q[++head];
exist[u]=false;
fpr(u的所有临界点v)
if(d[u]+w[u][v]<d[v])
{
d[v]=d[u]+w[u][v];
pre[v]=u;
if(!exist[v])
{q[++tail]=v;exist[v]=true;}
}
}
上一个例题吧,就上一个博客的那个题,看了题解他们用的双向spfa算法,最后做出来了。原题博客在这儿~~~
首先我们知道这个spfa算法是求出一个开始点到图中每个点的最短路径长度。
这是样例的图,因为这个题没有权值,所以我们需要对spfa变一变形,让他求出从开始点 开始,经过图中能够经过的新线路最后到达第i个点的最小/最大的水晶球的价格。,然后我们这个题的要求是从1点走到n点能够赚取最多的金钱的值,我们可以通过从i到n的最大水晶球价格减去从1出发到i点的最小水晶球价格最后就是赚取的钱数了。所以这就需要用两次的spfa算法,一次是正向的,一次是反向的。
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
int a[100001],tb[100001],ta[100001];
vector<int> g[100001],gf[100001];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;++i)
cin>>a[i];
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
g[x].push_back(y); //g是正向建图
gf[y].push_back(x); // gf是反向建图
if(z==2)
{
g[y].push_back(x);
gf[x].push_back(y);
}
}
queue<int> q;
q.push(1);
memset(ta,127,sizeof(ta));
ta[1]=2147483647;
//记录从1到i结点的最短路径的spfa算法
while(!q.empty())
{
int t=q.front();
q.pop();
ta[t]=min(ta[t],a[t]);
int l=g[t].size();
for(int i=0;i<l;i++)
if(ta[t]<ta[g[t][i]])
{
ta[g[t][i]]=ta[t];
q.push(g[t][i]);
}
}
//记录从i到n结点的最短路径的spfa算法
q.push(n);
while(!q.empty())
{
int t=q.front();
q.pop();
tb[t]=max(tb[t],a[t]);
int l=gf[t].size();
for(int i=0;i<l;i++)
if(tb[t]>tb[gf[t][i]]){
tb[gf[t][i]]=tb[t];
q.push(gf[t][i]); }
}
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,tb[i]-ta[i]);
cout<<ans<<endl;
return 0;
}
最后spfa的时间复杂度O(VE)
真的在家的效率真的是很低了,这个假期想学的还是蛮多的,希望自己的欲望能够战胜理智吧~~~~。