图论
首先
\(\color {red}{SPFA已死,Dijkstra当立!}\)
\(\small{\color {gray}{咳}}\)
前向星
struct edge{int to,next,v;}e[N<<1];
int en,head[N];
void addedge(int x,int y,int v)
{
e[++en]==(edge){y,head[x],v};
head[x]=en;
}
void dfs(int x)
{
for(int i=head[x];i;i=e[i].next;
{
int y=e[i].to;
dfs(y);
}
}
最短路图
1.没有负环
2.是DAG
bellman-ford
先将在、所有点的最短距离设为∞,起点为0(和dij一样)
然后对边集(边!)松弛两端端点
最后得记得检查一下
有了SPFA了要什么bellman-ford
SPFA
就是bellman-ford的priority_queue优化
\(\huge {但是}\)
\(\small {\color {grey}{它死了}}\)
咳
正经点
就是在bellman-ford的基础上将遍历所有点改为直接从queue取数
int dis[N],inq[N];
void spfa()
{
memeset(dis,0x3f,sizeof(dis);
queue<int> q;
q.push(1);
inq[1]=1;
dis[1]=0;
while(!q.emptu())
{
int x=q.front();
q.pop();
inq[x]=0;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(dis[y]>dis[x]+e[i].v)
{
dis[y]=dis[x]+e[i].v;
if(!inq[y])
{
q.push(y);
inq[y]=1;
}
}
}
}
}
把松弛的对比比较的大于号改成小于号就可以求最长路
- \(\small {\color {white}{但是有了Dijkstra要什么SPFA}}\)
Dijkstra
Dij我之前写过,所以
点我滚过去_(:з」∠)_
拓扑排序
将当前入度最小的(联想到priority_queue
)点向其他点探索,然后踢出去,找下一个入度最小的点,继续......
就这样
queue<int> q;
int rd[];//入度
void topsort()
{
for(int i=1;i<=n;i++)
if(rd[i]==0)
q.push(i);
while(!q.empty())
{
int x=q.front;
q.pop();
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
rd[y]--;
if(rd[y]==0)
q.push(y);
}
}
}
Floyd
经典老算法
时间复杂度\(O(n^3)\)
太经典了
不过第三维可以省掉了
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][j]+f[k][j]);
}
}
可以做传递闭包,可以跑得飞快
负环
1.负环可以用SPFA来判断($\small {SPFA突然又活了})
不过要把SPFA改成dfs,但是可能会当场T掉(如果出题人很恶心)
2.或者记录每个点的入队次数,只要有点入队次数大于n那就有负环
3.还有一个,开一个数组记录当前最短路有几个点,如果大于n,那就存在负环
在对比之下,1会被卡爆,2比3慢一些,所以用3
bool spfa()
{
queue<int> q;
memset(dis,0x3f,sizeof(dis));
memset(cnt,0,sizeof(cnt));
memset(inq,0,sizeof(inq));
dis[1]=0;
q.push(1);
inq[1]=cnt[1]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
inq[x]=0;
for(int i=1;i;i=e[i].next)
{
int y=e[i].to;
if(dis[y]>dis[x]+e[i].v)
{
cnt[y]=cnt[x]+1;
if(cnt[y]>n)
return true;
dis[y]=dis[x]+e[i].v;
if(!inq[y])
{
q.push(y);
inq[y]=1;
}
}
}
}
return false;
}