ACM模板——最短路

#include <bits/stdc++.h>
#define pb push_back
#define _for(i,a,b) for(int i = (a);i < (b);i ++)
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 50003;

struct edge
{
    int to;
    int cost;
};
vector<edge> G[maxn];
//G[s].push_back(t);from s to t,directed

int V,E;

//from s to other V
void shortest_path(int s)
{
    
}

int main()
{
    scanf("%d %d",&V,&E);
    _for(i,0,E)
    {
        int s,t,c;
        scanf("%d %d %d",&s,&t,&c);
        G[s].push_back(edge{t,c});
        G[t].push_back(edge{s,c});
    }
    shortest_path(0);
    cout << d[6] << endl;
}

/*
10
1 2
2 5
2 4
3 6
3 2
4 10
5 1
5 3
6 5
6 9
*/
main函数
//from s to other V
int d[maxn];
void shortest_path(int s)
{
    _for(i,0,V)
        d[i] = INF;

    d[s] = 0;
    while(1)
    {
        bool update = false;
        _for(i,0,V)
        {
            _for(j,0,G[i].size())
            {
                edge e = G[i][j];
                if(d[i] != INF && d[e.to] > d[i] + e.cost)
                {
                    d[e.to] = d[i] + e.cost;
                    update = true;
                }
            }
        }
        if(!update) break;
    }
}
Bellman-Ford
//from s to other V
bool used[maxn];
int d[maxn];
void shortest_path(int s)
{
    _for(i,0,V)
    {
        d[i] = INF;
        used[i] = false;
    }
    d[s] = 0;

    while(1)
    {
        int v = -1;
        _for(i,0,V)
        if(!used[i] && (v==-1 || d[i] < d[v])) v = i;

        if(v==-1) break;
        used[v] = true;

        _for(i,0,G[v].size())
        d[G[v][i].to] = min(d[G[v][i].to],d[v]+G[v][i].cost);
    }
}
Dijkstra
//from s to other V
typedef pair<int,int> P;//first 是最短距离,second 是顶点编号 
int d[maxn];
void shortest_path(int s)
{
    priority_queue<P,vector<P>,greater<P>> que;
    
    _for(i,0,V)
        d[i] = INF;
    d[s] = 0;
    que.push(P{0,s});

    while(!que.empty())
    {
        P p = que.top();que.pop();
        int v = p.second;
        if(d[v] < p.first) continue;
        _for(i,0,G[v].size())
        {
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost)
            {
                d[e.to] = d[v] + e.cost;
                que.push(P{d[e.to],e.to});
            }
        }
    }
}
Dijkstra(priority_queue)
//from s to other V
typedef pair<int,int> P;//first 是最短距离,second 是顶点编号 
int d[maxn];
int pre[maxn];
void shortest_path(int s)
{
    priority_queue<P,vector<P>,greater<P>> que;
    
    _for(i,0,V)
        d[i] = INF;
    _for(i,0,V)
        pre[i] = -1;
    d[s] = 0;
    que.push(P{0,s});

    while(!que.empty())
    {
        P p = que.top();que.pop();
        int v = p.second;
        if(d[v] < p.first) continue;
        _for(i,0,G[v].size())
        {
            edge e = G[v][i];
            if(d[e.to] > d[v] + e.cost)
            {
                d[e.to] = d[v] + e.cost;
                que.push(P{d[e.to],e.to});
                pre[e.to] = v;
            }
        }
    }
}

//到终点t 
vector<int> get_path(int t)
{
    vector<int> p;
    for(; t != -1;t = pre[t]) p.pb(t);
    reverse(p.begin(),p.end());
    return p;
}
Dijkstra(priority_queue)路径还原
bool find_negative_loop()
{
    memset(d,0,sizeof(d));
    _for(i,0,V)
        _for(j,0,V)
            _for(k,0,G[j].size())
            {
                edge e = G[j][k];
                if(d[e.to] > d[j] + e.cost)
                {
                    d[e.to] = d[j] + e.cost;
                    if(i==V-1) return true;
                }
            }
    return false;
}
判断负圈
//from s to other V
int d[maxn][maxn];
void shortest_path()
{
    memset(d,INF,sizeof(d));
    _for(i,0,V)
        _for(j,0,G[i].size())
        {
            edge e = G[i][j];
            d[i][e.to] = e.cost;
        }
    
    _for(k,0,V)
        _for(i,0,V)
            _for(j,0,V)
                d[i][j] = min(d[i][j],d[i][k]+d[k][j]);
}
Floyd-Warshall
//from s to other V
//return false表示有负圈
int d[maxn];// 距离数组 
int vis[maxn];// 判断点是否在队列里 
int pre[maxn];// 路径还原
int cnt[maxn];// 进队列次数 
bool shortest_path(int s)
{
    memset(d,INF,sizeof(d));
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    memset(pre,-1,sizeof(pre));
    
    deque<int> q;
    d[s] = 0,cnt[s] = vis[s] = 1;
    q.push_back(s);
    while(!q.empty())
    {
        int now = q.front();q.pop_front();
        vis[now] = 0;
        _for(i,0,G[now].size())
        {
            if(d[G[now][i].to] > d[now] + G[now][i].cost)
            {
                d[G[now][i].to] = d[now] + G[now][i].cost;
                pre[G[now][i].to] = now;
                if(!vis[G[now][i].to])
                {
                    if(V == ++cnt[G[now][i].to]) return false;
                    if(!q.empty() && d[G[now][i].to] < d[q.front()])//队列非空且优于队首(SLF)
                        q.push_front(G[now][i].to);
                    else q.push_back(G[now][i].to);
                    vis[G[now][i].to] = 1;
                }
            }
        }
    }
    return 0;
}

//到终点t 
vector<int> get_path(int t)
{
    vector<int> p;
    for(; t != -1;t = pre[t]) p.pb(t);
    reverse(p.begin(),p.end());
    return p;
}
SPFA(SLF优化,路径还原)

Bellman O(|V|*|E|),可处理负边

Dijkstra 优先队列实现 O(|E|*log|V|),不可处理负边

Floyd O(|V^3|) d[i][i]为负数时可判定有负圈

SPFA O(|V|*|E|),如果返回false则有负圈

posted @ 2019-03-20 17:30  Asurudo  阅读(233)  评论(0编辑  收藏  举报