这周把寒假没学的最短路看y总的课基本上学了学,然后今天全都自己手打一遍,记录一下我打的时候易错点。
朴素版的Dijkstra:
这个感觉还是好理解的,就是在更新t的时候条件,有直接一行写的但是要背,我背不出就靠理解写两个if然后里面条件不能忘特别是我写的第二个if的st[t]!=0;然后就是判断dist[n]是否存在是要大于等于0x3f3f3f3f。
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<vector>
typedef long long ll;
using namespace std;
const int N=505;
ll n,m;
ll bian[N][N];
ll dist[N];
bool st[N];
ll dijst(){
memset(dist,0x3f3f3f3f,sizeof dist);
dist[1]=0;
ll t=1;
for(int i=0;i<n;i++){
for(int j=1;j<=n;j++){
dist[j]=min(dist[j],dist[t]+bian[t][j]);
}
st[t]=1;
t=-1;
for(int j=1;j<=n;j++){
if(t==-1&&st[j]==0) t=j;
else if(t!=-1&&dist[j]<dist[t]&&st[j]==0)t=j;
}
}
if(dist[n]>=0x3f3f3f3f)return -1;
return dist[n];
}
int main(){
memset(bian,0x3f3f3f3f,sizeof bian);
cin>>n>>m;
while(m--){
ll a,b,c;
cin>>a>>b>>c;
bian[a][b]=min(bian[a][b],c);
}
ll ans=dijst();
cout<<ans;
}
堆优化版的Dijkstra:
折磨一天才看懂的堆优化板子,主要点在优先队列和邻接表对我来说是新东西。然后这几天每天写一遍堆优化,每天都有错的地方。注意点就是优先队列对于pair是按first排序,然后就是不存在时的范围。最主要的还是邻接表的建立。
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<vector>
typedef long long ll;
using namespace std;
const int N=1e6+10;
typedef pair<ll,ll>PII;
ll n,m;
ll ed[N],ne[N],w[N],h[N],idx;
bool st[N];
ll dist[N];
void add(ll a,ll b,ll c){
ed[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx;idx++;
}
ll dijst(){
memset(dist,0x3f3f3f3f,sizeof dist);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.pop();
ll dian=t.second,juli=t.first;
if(st[dian]==1)continue;
st[dian]=1;
for(int i=h[dian];i!=-1;i=ne[i]){
ll j=ed[i];
if(dist[j]>dist[dian]+w[i]){
dist[j]=dist[dian]+w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n]>=0x3f3f3f3f) return -1 ;
return dist[n];
}
int main(){
memset(h,-1,sizeof h);
cin>>n>>m;
while(m--){
ll a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
ll ans=dijst();
cout<<ans<<endl;
}
bellman_ford:
这个就是结构体然后暴力更新,理解起来比较简单,可以处理存在负环边的情况,主要难点就在于dist的备份因为不能,在有边的次数限制下,本次更新可能会影响后面的更新,然后就要备份一下。
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<vector>
typedef long long ll;
using namespace std;
const int N=1e5+10;
ll n,m,k;
struct hh{
ll a,b,c;
};
hh a[N];
ll dist[N];
ll last[N];
ll bemfd(){
memset(dist,0x3f3f3f3f,sizeof dist);
dist[1]=0;
for(int j=0;j<k;j++){
memcpy(last,dist,sizeof dist);
for(int i=1;i<=m;i++){
dist[a[i].b]=min(dist[a[i].b],last[a[i].a]+a[i].c);
}
}
return dist[n];
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=m;i++){
ll x,y,z;
cin>>x>>y>>z;
a[i].a=x;
a[i].b=y;
a[i].c=z;
}
ll ans=bemfd();
if(ans>=1e15) cout<<"impossible";
else cout<<ans<<endl;
}
spfa:
这个时上一个的优化,用队列和邻接表实现,只有在距离改变的时候才加入队列然后之后在更新之后的路。感觉重点还是在邻接表。
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<vector>
typedef long long ll;
using namespace std;
const int N=1e5+10;
ll n,m;
ll ed[N],ne[N],w[N],h[N],idx;
ll dist[N];
bool st[N];
void add(ll a,ll b,ll c){
ed[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx;idx++;
}
ll spfa(){
memset(dist,0x3f3f3f3f,sizeof dist);
dist[1]=0;
queue<ll>q;
q.push(1);
while(q.size()){
ll t=q.front();
st[t]=0;
q.pop();
for(int i=h[t];i!=-1;i=ne[i]){
ll j=ed[i];
if(dist[j]>dist[t]+w[i]){
if(st[j]==0){
q.push(j);
st[j]=1;
}
dist[j]=dist[t]+w[i];
}
}
}
return dist[n];
}
int main(){
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=1;i<=m;i++){
ll a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
ll ans=spfa();
if(ans>=1e15) cout<<"impossible";
else cout<<ans<<endl;
}
四种方法的总结,啥时候用。