我看维基百科的介绍, 加上iceboy某次给我的讲解, 写出来了一个。
SPFA 是一种很简单而且很快的算法用来求单源最短路(就是在一个有向图里面, 从一个点出发, 到达所有点的最短路径)。
需要的数据结构有一个数组和一个存有图的数组的数组(也叫做二维数组)。
数组里面存的是目前的解。
比如有 1 2 3 4 5 五个顶点从 1 出发, 那么数组里是 0 ∞ ∞ ∞ ∞
然后还需要一个队列, 把初始节点1放到队列里, 就可以开始 SPFA 了!
过程是这样的, 每次从队列里取出一个顶点。
然后枚举这个顶点的所有边。
如果能够找到一个更好的解, 就更新那个数组, 同时把被更新的点放到队列里。 //貌似叫做”松弛操作”
如果队列什么都没有了, 说明完成了。
就是这样。
这个题目就是判断有没有负权回路。
判断有没有负权回路只需要判断某点进入队列的次数, 大于n-1就说明存在负权回路。
下面这段代码是可以AC的, 那就不管别的了>_<。
#include<iostream> #include<queue> using namespace std; const int oo=0xFFFFFFF; int G[600][600],n,m,w; void init() { cin>>n>>m>>w; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) G[i][j]=oo; int s,e,t; for(int i=1;i<=m;++i) { cin>>s>>e>>t; G[e][s]=G[s][e]=min(G[s][e],t); } for(int i=1;i<=w;++i) { cin>>s>>e>>t; t=-t; G[s][e]=min(G[s][e],t); } } bool SPFA() { int ln[600],counter[600]; bool inqueue[600]; queue<int> Q; for(int i=1;i<=n;++i) { ln[i]=0; //有一个神奇的点, 使得它到每个点距离为0 Q.push(i); counter[i]=1; inqueue[i]=true; } while(!Q.empty()) { int index=Q.front(); Q.pop(); inqueue[index]=false; for(int i=1;i<=n;++i) { if(ln[index]+G[index][i]<ln[i]) { ln[i]=ln[index]+G[index][i]; if(!inqueue[i]) //原来这里用stl的find函数, 结果TLE了=w= { Q.push(i); ++counter[i]; inqueue[i]=true; if(counter[i]>n-1) return true; } } } } return false; } int main() { int F; cin>>F; while(F--) { init(); cout<<(SPFA()?"YES":"NO")<<endl; } return 0; }
话说为什么在poj上用G++和C++得到的结果不一样, 它们分别用了什么编译器, 求解。
Run ID | User | Problem | Result | Memory | Time | Language | Code Length | Submit Time |
10809889 | twd2 | 3259 | Accepted | 1888K | 1813MS | G++ | 1391B | 2012-09-15 17:41:19 |
10809888 | twd2 | 3259 | Accepted | 1420K | 1016MS | C++ | 1391B | 2012-09-15 17:41:09 |
然后Mrw神牛看到了这篇文章, 吐槽了我的邻接矩阵(int G[600][600]), 告诉我有邻接表这么个东西。
于是修改代码如下
#include<iostream> #include<queue> #include<vector> using namespace std; const int oo=0xFFFFFFF; class edge { public: int v, ln; edge() : v(0), ln(0) {} edge(int v, int ln) : v(v), ln(ln) {} }; int n,m,w; vector<edge> G[600]; void init() { cin>>n>>m>>w; for(int i=1;i<=n;++i) { G[i].clear(); } int s,e,t; for(int i=1;i<=m;++i) { cin>>s>>e>>t; G[s].push_back(edge(e,t)); G[e].push_back(edge(s,t)); } for(int i=1;i<=w;++i) { cin>>s>>e>>t; G[s].push_back(edge(e,-t)); } } bool SPFA() { int ln[600],counter[600]; bool inqueue[600]; queue<int> Q; for(int i=1;i<=n;++i) { ln[i]=0; Q.push(i); counter[i]=1; inqueue[i]=true; } while(!Q.empty()) { int index=Q.front(); Q.pop(); inqueue[index]=false; for(vector<edge>::iterator it=G[index].begin();it<G[index].end();++it) { if(ln[index]+it->ln<ln[it->v]) { ln[it->v]=ln[index]+it->ln; if(!inqueue[it->v]) { Q.push(it->v); ++counter[it->v]; inqueue[it->v]=true; if(counter[it->v]>n-1) return true; } } } } return false; } int main() { int F; cin>>F; while(F--) { init(); cout<<(SPFA()?"YES":"NO")<<endl; } return 0; }
于是评测结果
Run ID | User | Problem | Result | Memory | Time | Language | Code Length | Submit Time |
10811170 | twd2 | 3259 | Accepted | 784K | 516MS | G++ | 1636B | 2012-09-15 22:34:33 |
10811169 | twd2 | 3259 | Accepted | 332K | 282MS | C++ | 1636B | 2012-09-15 22:34:10 |
发表评论