Bellman Ford
进行n-1轮(最多n-1层,就是[0,n-2]),每次将所有的边松弛,如果进行之后还能松弛,说明是负环
这个复杂度是O(VE),dijkstra是O(V^2+E)
- 使用邻接表而不是邻接矩阵,邻接矩阵复杂度会上升
- 邻接表在使用边的时候,判断好Adj[u][j]是对应的边,d[Adj[u][j].v]是对应边终点的d,中间距离dis是Adj[u][j].dis,这段容易搞错
- 使用set要用insert,因为多轮松弛肯定会多次反复访问重复点,因此要用set
- 在相等的时候,num的修改就是清零重新计算。(这个也导致不能存完pre等结束以后全部重新计算)
- 初始num[st]=1;
#include<stdio.h> #include<string.h> #include<set> #include<vector> using namespace std; int n,m,st,ed; const int INF=10000; int d[1000],w[1000],num[1000];//w代表累计,num是路径数 set<int>pre[1000]; int weight[1000]={0}; struct Node{ int v; int dis; Node(int tempv,int tempdis) { v=tempv; dis=tempdis; } }; vector<Node>Adj[1000]; void Bellman(int st) { fill(d,d+n,INF); memset(num,0,sizeof(num)); for(int i=0;i<=n-1;i++) w[i]=weight[i]; /*memset(w,0,sizeof(w)); w[st]=weight[st];*/ d[st]=0; num[st]=1; for(int i=0;i<n-1;i++) { for(int u=0;u<=n-1;u++) { for(int j=0;j<Adj[u].size();j++) { int temp=Adj[u][j].v; if(d[temp]>d[u]+Adj[u][j].dis) { pre[temp].clear(); pre[temp].insert(u); w[temp]=w[u]+weight[temp]; d[temp]=d[u]+Adj[u][j].dis; } else if(d[temp]==d[u]+Adj[u][j].dis) { pre[temp].insert(u); w[temp]=max(w[temp],(w[u]+weight[temp])); set<int>::iterator it=pre[temp].begin(); num[temp]=0; for(it=pre[temp].begin();it!=pre[temp].end();it++) { num[temp]+=num[*it]; } } } } } } int main() { scanf("%d %d %d %d",&n,&m,&st,&ed); for(int i=0;i<=n-1;i++) scanf("%d",&weight[i]); for(int i=1;i<=m;i++) { int temp1,temp2,temp3; scanf("%d %d %d",&temp1,&temp2,&temp3); Adj[temp1].push_back(Node(temp2,temp3)); Adj[temp2].push_back(Node(temp1,temp3)); } Bellman(st); printf("%d %d",num[ed],w[ed]); return 0; }
A1003的代码。
floyd是用来解决多源最短路,复杂度o3
注意,这个本质上是贪心,在i-j的路径上有一堆点,每次通过一个点松弛,在松弛到最大点的时候,他的左边和右边都取到了最小值,那么他也是,往里推也一样,所以三层循环成立。
每次选好点以后,对整个图松弛,所以选点在最外层。
关于fill函数
fill(a,a+n,INF)
如果是二维数组fill(a[0],a[0]+maxn*maxn,INF)
a[0]才是首地址
fill在iostream头文件里面
以有向图为例的floyd代码
#include<stdio.h> #include<iostream> using namespace std; int n,m,G[100][100]={0}; const int INF=10000; int main() { scanf("%d %d",&n,&m); fill(G[0],G[0]+100*100,INF); for(int i=1;i<=m;i++) { int temp1,temp2,temp3; scanf("%d %d %d",&temp1,&temp2,&temp3); G[temp1][temp2]=temp3; //G[temp2][temp1]=temp3; } for(int i=0;i<=n-1;i++) G[i][i]=0; for(int k=0;k<=n-1;k++) { for(int i=0;i<=n-1;i++) { for(int j=0;j<=n-1;j++) G[i][j]=min(G[i][j],(G[i][k]+G[k][j])); } } for(int i=0;i<=n-1;i++) { for(int j=0;j<=n-1;j++) { printf("%d ",G[i][j]); } printf("\n"); } return 0; }
时间才能证明一切,选好了就尽力去做吧!