大致的算法:
struct Node{ int v,dis; }; vector<Node>Adj[MAXV]; int n,d[MAXV]; bool Bellman(int s) { fill(b,b+MAXV,INF); d[s]=0; for(int i=0;i<n-1;i++) { for(int u=0;u<n;u++) { for(int j=0;j<Adj[u].size();j++) { int v=Adj[u][j].v , dis = Adj[u][j].dis; if(d[u]+dis<d[v]) { d[v]=d[u]+dis; //松弛操作 } } } } //判断是否有负环的代码 for(int u=0;u<n;u++) { for(int j=0;j<Adj[u].size();j++) { int v=Adj[u][j].v , dis = Adj[u][j].dis; if(d[u]+dis<d[v]) { //d[v]=d[u]+dis;松弛操作 return false; } } } return true; }
实例:一般正常的没有源点可达的负环
因此判断负环的过程可以省略。
#include<cstdio> #include<vector> #include<set> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int MAXV = 1000; const int INF = 0xFFFFFFF; struct Node{ int v,dis;; Node(int _v,int _dis){ v=_v ; dis=_dis; } }; vector<Node>Adj[MAXV]; int n,m,st,ed,weight[MAXV]; int d[MAXV],w[MAXV],num[MAXV]; set<int>pre[MAXV]; //使用邻接表实现,因为邻接矩阵的复杂度达到O(V^3),而邻接表只有O(VE) bool Bellman(int s) { fill(d,d+MAXV,INF); memset(w,0,sizeof(w)); memset(num,0,sizeof(num)); d[s]=0; w[s]=weight[s]; num[s]=1; for(int i=0;i<n-1;i++) //n-1操作 { for(int u=0;u<n;u++) { for(int j=0;j<Adj[u].size();j++) { int v=Adj[u][j].v; int dis=Adj[u][j].dis; if(d[u]+dis<d[v]) { d[v]=d[u]+dis; num[v]=num[u]; w[v]=w[u]+weight[v]; pre[v].clear(); pre[v].insert(u); } else if(d[u]+dis==d[v]) { if(w[u]+weight[v]>w[v]) { w[v]=w[u]+weight[v]; } pre[v].insert(u); num[v]=0; set<int>::iterator it; for(it=pre[v].begin();it!=pre[v].end();it++) num[v]+=num[*it]; } } } } /* 省略了判断是否存在负环的操作 for(int u=0;u<n;u++) { for(int j=0;j<Adj[u].size();j++) { int v=Adj[u][j].v; int dis=Adj[u][j].dis; if(d[u]+dis<d[v]) { return false; } } } */ return true; } int main(void) { scanf("%d%d%d%d",&n,&m,&st,&ed); for(int i=0;i<n;i++) scanf("%d",&weight[i]); int u,v,wt; for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&wt); Adj[u].push_back(Node(v,wt)); Adj[v].push_back(Node(u,wt)); } Bellman(st); printf("%d %d ",num[ed],w[ed]); return 0; }