#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<ctime>
#define MAXX 1e6
using namespace std;
int first[1000010],NEXT[1000010],u[1000010],v[1000010],w[1000010],cont,dis[1000010],vis[1000010];//c存起点,v存终点,w存权值
int N,M,S,T;
bool buildmap(int a,int b,int c)//建图
{
u[cont]=a,v[cont]=b,w[cont]=c;//存边
NEXT[cont]=first[a];
first[a]=cont;
cont++;
}
void BellmanDU()//Bellman队列优化
{
queue<int> q;
memset(dis,-1,sizeof(dis));//标记从起点到各个点的最短路
memset(vis,0,sizeof(vis));//标记点是否在队列里
q.push(S);
vis[S]=1;
dis[S]=0;
while(!q.empty())
{
int s=q.front();
q.pop();
vis[s]=0;
int k=first[s];
while(k!=-1)//遍历以s为起点的所有点
{
if(dis[v[k]]==-1||(dis[v[k]]>dis[u[k]]+w[k]))//是否松弛成功
{
dis[v[k]]=dis[u[k]]+w[k];
if(!vis[v[k]])//该点是否在队列里
{
vis[v[k]]=1;
q.push(v[k]);//入队
}
}
k=NEXT[k];//下一条边
}
}
}
void Bellman()//Bellman算法
{
memset(dis,-1,sizeof(dis));//初始化
dis[S]=0;
for(int i=1; i<=N-1; i++) //松弛N-1次
for(int j=1; j<=M; j++) //判断每条边
if(dis[v[j]]==-1||dis[v[j]]>dis[u[j]]+w[j])
dis[v[j]]=dis[u[j]]+w[j];
/*flag=0;//检测负权回路
for(int j=1;j<=M;j++)
if(dis[v[j]]>dis[u[j]]+w[j])
flag=1;
if(flag)
printf("此图含有负权回路\n");*/
}
int main()
{
while(~scanf("%d%d%d%d",&N,&M,&S,&T))//点,边,起点,终点
{
memset(first,-1,sizeof(first));//first存以下标为起点的第一条边的标号,标号为u,v,w三个数组的下标
cont=1;
for(int i=0; i<M; i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
buildmap(a,b,c);
buildmap(b,a,c);//双向图
//有可能有重边
}
Bellman();//BellmanDU();
printf("%d\n",dis[T]);
}
}
Bellman及其优化
最新推荐文章于 2021-11-19 11:14:58 发布