SPFA

来源:互联网 发布:上海徒步俱乐部 知乎 编辑:程序博客网 时间:2024/06/14 09:25

SPFA

单源最短路 ,

可以处理负权边,判断负权环

复杂度 O(K*E),据说K可以证明不会大于2。

hdu 2066

#include <map>#include <set>#include <cmath>#include <queue>#include <string>#include <cstdio>#include <vector>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int N=1005;const int INF=0x3f3f3f3f;#define pb push_back#define fi first#define se second#define mp mak_pair#define pii pair<int,int>struct edge {      int v,cost;      edge(int _v=0,int _cost=0):v(_v),cost(_cost) {}};vector<edge> es[N];void addEdge(int u,int v,int w) {      es[u].pb(edge(v,w));}bool vis[N];int dis[N],cnt[N];//cnt 每个点入队的次数bool SPFA(int s) {    memset(cnt,0,sizeof cnt);    memset(vis,false,sizeof vis);    for(int i=0;i<N;++i) dis[i]=INF;    vis[s]=true;    dis[s]=0;    queue<int> que;    que.push(s);    while(!que.empty()) {        int u=que.front(); que.pop();        int sz=es[u].size();        vis[u]=false;        for(int i=0;i<sz;++i) {            int v=es[u][i].v;            if(dis[u]+es[u][i].cost<dis[v]) {                dis[v]=dis[u]+es[u][i].cost;                if(vis[v]==false) {                    vis[v]=true;                    que.push(v);                    if(++cnt[v]>n) return false;//存在负权环                }            }        }    }    return true;}int st[N],ed[N];int main() {      int t,s,d,x,y,c;      while(~scanf("%d%d%d",&t,&s,&d)) {            for(int i=0;i<N;++i) es[i].clear();            while(t--) {                  scanf("%d%d%d",&x,&y,&c);                  addEdge(x,y,c);                  addEdge(y,x,c);            }            for(int i=1;i<=s;++i) scanf("%d",&st[i]);            for(int i=1;i<=d;++i) scanf("%d",&ed[i]);            int ans=INF;            for(int i=1;i<=s;++i) {                SPFA(st[i]);                for(int j=1;j<=d;++j) ans=min(ans,dis[ed[j]]);            }            printf("%d\n",ans);      }    return 0;}

邻接表实现

int cnt=0;int last[N];struct edge {      int to,pre,cost;}es[2*N];void addEdge(int u,int v,int w) {    edge e={v,last[u],w};    es[++cnt]=e;    last[u]=cnt;}// last[i] 从i出发的最后一条边的编号// pre 前一条边的编号bool vis[N];int dis[N],cnt[N];//cnt 每个点入队的次数bool SPFA(int s) {    memset(cnt,0,sizeof cnt);    memset(vis,false,sizeof vis);    for(int i=0;i<N;++i) dis[i]=INF;    vis[s]=true;    dis[s]=0;    queue<int> que;    que.push(s);    while(!que.empty()) {        int u=que.front(); que.pop();        vis[u]=false;        for(int i=last[u];i!=-1;i=es[i].pre) {            int v=es[i].to;            if(dis[u]+es[i].cost<dis[v]) {                dis[v]=dis[u]+es[i].cost;                if(!vis[v]) {                    vis[v]=true;                    que.push(v);                    if(++cnt[v]>n) return false;                }            }        }    }    return true;}int st[N],ed[N];
邻接表实现方式如下图

这里写图片描述

last数组存从i出发的最后一条边的编号
pre存上一条边的编号
vis存是否在缓冲队列中

0 0
原创粉丝点击