最短路——SPFA
2016-01-30 10:30
405 查看
bellman算法有太多冗余的松弛操作,SPFA利用队列省去了冗余的讨论,时间复杂度约为O(KE)k约为2,E为边数。
代码如下:
根据算法原理,每个点最多只会入队n次,如过某个点入队达到n+1(这是血的教训)次,那么该图中有负权回路。
以下是利用边存储的结构体形式的SPFA,并且带有负权回路判定的代码
last[x] 表示以x为起点的最后一条边
next[x]表示和x边同起点的下一条边,0表示没有了
edge是存储边的数组
代码如下:
#include<cstdio> #include<iostream> #include<queue> const int inf=10000000; using namespace std; queue<int>q; int n,m,x,y,map[105][105],vis[105],dist[105]; // vis[i]记录i是否在队列中; void input(){ int p,q,i,j,t; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i!=j)map[i][j]=inf; for(i=1;i<=m;i++){ scanf("%d%d%d",&p,&q,&t); map[p][q]=t; } scanf("%d%d",&x,&y); } void SPFA(){ int i,j; for(i=1;i<=n;i++)dist[i]=inf; //初始化 dist[x]=0; q.push(x); vis[x]=true; while(!q.empty()){ int cur=q.front(); //取队首元素 q.pop(); vis[cur]=false; //及时修正标记 for(i=1;i<=n;i++) if(dist[cur]+map[cur][i]<dist[i]){ dist[i]=dist[cur]+map[cur][i]; if(!vis[i]){vis[i]=true;q.push(i);} } } printf("%d",dist[y]); } int main(){ input(); SPFA(); }
根据算法原理,每个点最多只会入队n次,如过某个点入队达到n+1(这是血的教训)次,那么该图中有负权回路。
以下是利用边存储的结构体形式的SPFA,并且带有负权回路判定的代码
last[x] 表示以x为起点的最后一条边
next[x]表示和x边同起点的下一条边,0表示没有了
edge是存储边的数组
<pre name="code" class="cpp">#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<vector> #define LL long long #define CLEAR(XXX) memset((XXX),0,sizeof(XXX)) using namespace std; const LL inf=1000000000000LL; const int maxn=1005,maxm=100005; inline void _read(int &x){ char ch=getchar(); bool mark=false; for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true; for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0'; if(mark)x=-x; } struct Edge{ int from,to,w; Edge(int from,int to,int w):from(from),to(to),w(w){} }; struct SPFA{ int n,m; vector<Edge> edge; int last[maxm],Next[maxm]; LL dist[maxn]; int cnt[maxn]; bool vis[maxn]; void init(int n){ this->n = n; m=0; CLEAR(last); CLEAR(Next); edge.clear(); edge.push_back(Edge(0,0,0)); } void add_edge(int from,int to,int dist){ edge.push_back(Edge(from,to,dist)); m=edge.size()-1; Next[m]=last[from]; last[from]=m; } bool solve(int s){ int i; CLEAR(vis); CLEAR(cnt); for(i=1;i<=n;i++) dist[i]=inf; dist[s]=0; vis[s]=true;cnt[s]++; queue <int> q; q.push(s); while(!q.empty()){ int x=q.front(); q.pop();vis[x]=false; //及时修改标记 for(i=last[x];i;i=Next[i]){ Edge& e=edge[i]; if(dist[e.from]+e.w<dist[e.to]){ dist[e.to]=dist[e.from]+e.w; if(!vis[e.to]){ cnt[e.to]++; //统计入队次数,判断负权回路 if(cnt[e.to]==n+1)return false; q.push(e.to) ; vis[e.to]=true; } } } } return true; } void answer(){ for(int i=1;i<=n;i++) if(dist[i]>=inf)printf("NoPath\n"); else printf("%I64d\n",dist[i]); } }; int main(){ SPFA spfa; int n,m,s,i,from,to,dist; _read(n);_read(m);_read(s); spfa.init(n); for(i=1;i<=m;i++){ _read(from);_read(to);_read(dist); spfa.add_edge(from,to,dist); } if(spfa.solve(s))spfa.answer(); else printf("negetive loop"); return 0; }
相关文章推荐
- 配置多端口虚拟主机
- classloader和双亲加载模式
- mysql的内建字符串函数
- 微信支付 跳转只有一个确定按钮的坑
- HDOJ 2516-取石子游戏
- Wunder Fund Round 2016 (Div. 1 + Div. 2 combined)--B. Guess the Permutation
- windows环境下安装配置dlib(下)
- Linux Shell编程进阶案例实战(三)
- electron的安装
- RPi 2B Documentation
- Android中WebView使用详解
- mysql之视图
- LintCode : 编辑距离
- SQL Server执行计划的理解【转】
- CentOS 6.5 下安装 Redis 2.8.7
- mysql五种外键约束的含义
- v4l2 编程接口(二) — driver
- linux navicat 过期 解决办法
- 洛谷-谁拿了最多奖学金-NOIP2005提高组复赛
- 路由的概念与路由器设置 --鸟哥服务器架设篇学习