最短路....

这周把寒假没学的最短路看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;
}

 四种方法的总结,啥时候用。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值