最短路专题
最短路
F l o y d Floyd Floyd 算法 O ( n 3 ) O(n^3) O(n3)
最短路
for(register int k=1;k<=n;k++)
for(register int i=1;i<=n;i++)
for(register int j=1;j<=n;j++)
Dp[i][j]=min(Dp[i][j],Dp[i][k]+Dp[k][j]);
判负环
如果
D
p
x
,
y
<
0
Dp_{x,y}<0
Dpx,y<0 那么存在负环
.
.
.
可以运用动态规划输出路径的方法输出负环
.
.
.
传递闭包
在交际网络中 , , , 给定若干个元素和若干对二元关系 , , , 且关系具有传递性 . . . " " " 通过传递性推导出尽量多的元素之间的关系 " " " 的问题叫做传递闭包 . . .
建立邻接矩阵 d , d, d, 其中 d i , j = 1 d_{i,j}=1 di,j=1 表示 i i i 与 j j j 有关系 , , , d i , j = 0 d_{i,j}=0 di,j=0 表示 i i i 与 j j j 没有关系 . . . 特别的 , , , d i , i d_{i,i} di,i 始终为 1. 1. 1. 使用 F l o y d Floyd Floyd 算法可以解决 . . .
for(register int k=1;k<=n;k++)
for(register int i=1;i<=n;i++)
for(register int j=1;j<=n;j++)
Dp[i][j]|=Dp[i][k]&Dp[k][j];
B e l l m a n F o r d B f s BellmanFordBfs BellmanFordBfs 算法
最短路
判负环
普通算法 O ( n m ) O(nm) O(nm)
千万小心 , , , s i z e v sizev sizev 是连通块中点的个数 . . .
T o t Tot Tot 和 C n t Cnt Cnt 是互相独立的 , , , 可以只留一个 , , , C n t Cnt Cnt 效率更高 . . .
const int MaxN=2100;
const int MaxM=5100;
ShortestPathGraphs<int,MaxN,MaxM>G;
Queues<int,1100>Q;
bool Visit[MaxN];
int Dist[MaxN],Cnt[MaxN],Tot[MaxN];
inline bool BellmanFord(int start,int sizev){
memset(Tot,0,sizeof(int)*(sizev+1));Tot[start]=1;//入队次数
memset(Cnt,0,sizeof(int)*(sizev+1));//从start出发到 i 的最短路的边数
memset(Dist,0x3f,sizeof(Dist));Dist[start]=0;
memset(Visit,false,sizeof(Visit));
Q.Clear();Q.Push(start);
while(!Q.Empty()){
int from=Q.Front();Q.Pop();Visit[from]=false;
for(register int k=G.Last[from];k!=-1;k=G.Next[k]){
if(Dist[G.To[k]]>Dist[from]+G.Cost[k]){
Dist[G.To[k]]=Dist[from]+G.Cost[k];
Cnt[G.To[k]]=Cnt[from]+1;
if(Cnt[G.To[k]]>sizev)return true;
if(!Visit[G.To[k]]){
Visit[G.To[k]]=true;
Q.Push(G.To[k]);
if(++Tot[G.To[k]]==sizev)return true;
}
}
}
}
return false;
}
int n,m;
int main(){
int Test=1;Read(Test);
while(Test--){
Read(n),Read(m);
G.Clear();
for(register int i=1,x,y,c;i<=m;i++){
Read(x),Read(y),Read(c);
Insert(G,x,y,c);
if(c>=0)Insert(G,y,x,c);
}
if(BellmanFord(1,n))printf("YES\n");
else printf("NO\n");
}
return 0;
}
B i t s e t Bitset Bitset 优化 O ( n 2 m ω ) O(\frac{n^2m}{\omega}) O(ωn2m)
const int MaxN=2100;
const int MaxM=5100;
bitset<MaxN>Cnt[MaxN];
ShortestPathGraphs<int,MaxN,MaxM>G;
Queues<int,1100>Q;
bool Visit[MaxN];
int Dist[MaxN];
inline bool BellmanFord(int start,int sizev){
for(register int i=1;i<=sizev;i++)
Cnt[i].reset();
//Cnt[i]代表的是start到i的最短路的经过的点
memset(Dist,0x3f,sizeof(int)*(sizev+1));
memset(Visit,false,sizeof(bool)*(sizev+1));
Q.Clear();Q.Push(start);
Cnt[start].set(start);
Dist[start]=0;
while(!Q.Empty()){
int from=Q.Front();Q.Pop();Visit[from]=false;
//防止有自环权值为负
for(register int k=G.Last[from];k!=-1;k=G.Next[k]){
if(Dist[G.To[k]]>Dist[from]+G.Cost[k]){
if(Cnt[from][G.To[k]])return true;
Dist[G.To[k]]=Dist[from]+G.Cost[k];
Cnt[G.To[k]]=Cnt[from];
Cnt[G.To[k]].set(G.To[k]);
if(Visit[G.To[k]]==false){
Visit[G.To[k]]=true;
Q.Push(G.To[k]);
}
}
}
}
return false;
}
T a r j a n Tarjan Tarjan 算法优化
const int MaxN=3e3;
const int MaxM=6e3;
int Last[MaxN];
int Next[MaxM],To[MaxM],cnt;
long long Cost[MaxM];
inline void Insert(int from,int to,long long cost){
To[cnt]=to;Cost[cnt]=cost;
Next[cnt]=Last[from];Last[from]=cnt++;
}
int Dfn[MaxN],Low[MaxN],Belong[MaxN],tot,scc;
int Size[MaxN];
bool InSta[MaxN];
Stacks<int,MaxN>S;
inline void Tarjan(int from){
Dfn[from]=Low[from]=++tot;
S.Push(from);InSta[from]=true;
for(int k=Last[from];k!=-1;k=Next[k]){
if(!Dfn[To[k]]){
Tarjan(To[k]);
Low[from]=Min(Low[from],Low[To[k]]);
}
else if(InSta[To[k]])
Low[from]=Min(Low[from],Dfn[To[k]]);
}
if(Low[from]==Dfn[from]){
int now;scc++;
do{
now=S.Top();S.Pop();
Belong[now]=scc;
Size[scc]++;
InSta[now]=false;
}while(now!=from);
}
}
long long Dist[MaxN];
int Cnt[MaxN];
bool Visit[MaxN];
Queues<int,MaxN>Q;
inline void Join(int from){
Q.Push(from);Dist[from]=0;
Cnt[from]=0;Visit[from]=true;
for(int k=Last[from];k!=-1;k=Next[k])
if(!Visit[To[k]])Join(To[k]);
}
inline bool BellmanFord(int sizev){
memset(Visit,false,sizeof(Visit));
Q.Clear();Join(1);
while(!Q.Empty()){
int from=Q.Front();Q.Pop();Visit[from]=false;
for(int k=Last[from];k!=-1;k=Next[k]){
if(Belong[from]!=Belong[To[k]])continue;
if(Dist[To[k]]>Dist[from]+Cost[k]){
Dist[To[k]]=Dist[from]+Cost[k];
Cnt[To[k]]=Cnt[from]+1;
if(Cnt[To[k]]>=Size[Belong[To[k]]])return true;
if(!Visit[To[k]]){
Visit[To[k]]=true;
Q.Push(To[k]);
}
}
}
}
return false;
}
inline void ReInit(){
cnt=tot=scc=0;
memset(Last,-1,sizeof(Last));
memset(Dfn,0,sizeof(Dfn));
memset(Low,0,sizeof(Low));
memset(InSta,false,sizeof(InSta));
memset(Size,0,sizeof(Size));
memset(Belong,0,sizeof(Belong));
}
D i j k s t r a Dijkstra Dijkstra 算法
正权最短路 O ( m log n ) / O ( n 2 ) O(m\log n)/O(n^2) O(mlogn)/O(n2)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int InSize=(1<<20)+1;
const long long LInf=0x3f3f3f3f3f3f3f3f;
int input=InSize;
char InPut[InSize];
inline char GetChar()
{
if(input>=InSize)fread(InPut,1,InSize,stdin),input=0;
return InPut[input++];
}
#define GetChar() getchar()
template<typename Typename>
inline void Read(Typename& s)
{
s=0;register char c=GetChar();
while(c>'9'||c<'0')c=GetChar();
while(!(c>'9'||c<'0')){s=s*10+c-48;c=GetChar();}
}
template<typename Typename>
inline Typename Min(const Typename&x,const Typename&y){
if(x<y)return x;return y;
}
template<typename Typename>
inline Typename Max(const Typename&x,const Typename&y){
if(x>y)return x;return y;
}
template<typename Typename>
inline void Swap(Typename&x,Typename&y){
Typename t=x;x=y;y=t;
}
template<typename Typename,int MaxCnt>
struct Heaps{
private:
Typename Data[MaxCnt];
int size;
inline void UpFix(int now){
int i=now>>1,j=now;//Dad[j]=i;
while(i!=0){
if(Data[i]<Data[j])break;
Swap(Data[i],Data[j]);
i>>=1;j>>=1;
}
}
inline void DownFix(int now){
int i=now,j=now<<1;
while(j<=size){
if(j+1<=size&&Data[j+1]<Data[j])j++;
if(Data[i]<Data[j])break;
Swap(Data[i],Data[j]);
i=j;j<<=1;
}
}
public:
Heaps(){
size=0;
}
inline void Clear(){size=0;}
inline void Push(const Typename&x){
if(size==MaxCnt-1)puts("Error Heap");
else{
Data[++size]=x;
UpFix(size);
}
}
inline void Pop(){
Data[1]=Data[size--];
DownFix(1);
}
inline Typename Top(){
if(size==0){puts("Error Heap");return Typename();}
else return Data[1];
}
inline bool Empty(){return size==0;}
inline int Size(){return size;}
};
template<typename TypenameC,int MaxN,int MaxM>
struct ShortestPathGraphs{
typedef TypenameC costtype;
int Last[MaxN],cntn;
int Next[MaxM],To[MaxM],cntm;
costtype Cost[MaxM];
ShortestPathGraphs(){
cntn=cntm=0;
memset(Last,-1,sizeof(Last));
}
inline void Clear(){
cntn=cntm=0;
memset(Last,-1,sizeof(Last));
}
};
template<typename TypenameG>
inline void Insert(TypenameG&G,int from,int to,typename TypenameG::costtype cost){
G.To[G.cntm]=to;G.Cost[G.cntm]=cost;
G.Next[G.cntm]=G.Last[from];G.Last[from]=G.cntm++;
}
template<typename Typename1,typename Typename2>
struct Pairs{
Typename1 x;Typename2 y;
Pairs(){}
Pairs(const Typename1&_x,const Typename2&_y):
x(_x),y(_y){}
inline bool operator<(const Pairs&p){
return x==p.x?y<p.y:x<p.x;
}
};
const int MaxN=1e5+1e4;
const int MaxM=2e5+1e4;
ShortestPathGraphs<long long,MaxN,MaxM>G;
Heaps<Pairs<long long,int>,MaxN>H;
long long Dist[MaxM];
inline void Dijkstra(int start){
memset(Dist,0x3f,sizeof(Dist));
Dist[start]=0;H.Clear();
H.Push(Pairs<long long,int>(Dist[start],start));
while(!H.Empty()){
while(!H.Empty()&&H.Top().x!=Dist[H.Top().y])H.Pop();
if(H.Empty())break;
int from=H.Top().y;H.Pop();
for(register int k=G.Last[from];k!=-1;k=G.Next[k]){
if(Dist[G.To[k]]>Dist[from]+G.Cost[k]){
Dist[G.To[k]]=Dist[from]+G.Cost[k];
H.Push(Pairs<long long,int>(Dist[G.To[k]],G.To[k]));
}
}
}
}
int n,m,srt;
int main()
{
Read(n);Read(m);Read(srt);
for(register int i=1;i<=m;i++)
{
register int a,b;
register long long c;
Read(a);Read(b);Read(c);
Insert(G,a,b,c);
}
Dijkstra(srt);
for(register int i=1;i<=n;i++)
if(Dist[i]==LInf)printf("2147483647 ");
else printf("%lld ",Dist[i]);
return 0;
}
1302



被折叠的 条评论
为什么被折叠?



