5 5 1 2 20 2 3 30 3 4 20 4 5 20 1 5 100Sample Output
90
前面已经写过Bellman-Ford的算法了,但是这不是最简洁的,算法,一直在追求更简洁
书上说这种算法根据Be算法优化的
但是我感觉更像是用 Di算法优化的(个人意见)
为什么那?
Di算法是根据点来找最短路,这种算法也是,两种方法更新最短路的方法几乎一样
为什么说是Di的优化,哪里优化了
首先回顾一下Di算法为何不能有负权边
DI算法的时间比较短,是什么保证了它比Be的时间更短
是Di算法中的每一个点只找一次,即当所有边权为正时
不会存在一个路程更短的点来更新相邻的点,所以这个点真真正正只用找一次
下一次就不必动了,但是如果有负权边当拓展到负权边的时候又会产生新的最短路
前面的就需要再动一动了,这时候Di算法就出错了,算法的核心不成立了
但是!!!!
Be优化算法(目前介绍的算法)用了一个队列把需要更改的点存起来再更改一遍
通俗来说就是 我每次更新一个最短路,那么就有一个点有了新的最短路径,那么我把这个点
存起来,等等再来更新这个点,直到我存的点全部更新完
这样即使有负权边前面的点的最短路变了,但是我把点存起来了,一会再更新
这样负权边也没有影响了
但是!!!!
相对的,由于我又扭头更新了几次数据,那么我的时间复杂度也肯定要增加
所以也就没有Di算法快
ps :以上均为一个菜鸟的个人看法,如有错误,请大犇指出!
下面就上一下代码
#include
#include
using namespace std;
int u[4005],v[4005],w[4005];
int first[4001],next[4001];
int dis[1005],book[1005];
#define inf 99999999
int main()
{
int t,n;
queue q;
while(scanf("%d%d",&t,&n)!=EOF)
{
int k,a,b,c,d;
for(int i=1; i<=2*t; i++) //first 初始化一下准备开始建图
{
first[i]=-1;
}
for(int i=1;i<=n;i++)
{
book[i]=0; //初始化 表示栈里面没有元素
dis[i]=inf;
}
dis[1]=0;
for(int i=1; i<=2*t; i+=2)
{
scanf("%d%d%d",&a,&b,&c);
u[i]=a,v[i]=b,w[i]=c;
u[i+1]=b,v[i+1]=a,w[i+1]=c;
}
/*for(int i=1;i<=2*t;i++)
{
printf("%d %d %d*\n",u[i],v[i],w[i]);
}*/
for(int i=1;i<=2*t;i++)
{
next[i]=first[u[i]];
first[u[i]]=i;
}
/*for(int i=1;i<=2*t;i++)
{
printf("[%2d] %2d %2d*.*\n",i,first[i],next[i]);
}*/
q.push(1);
book[1]=1;
while(!q.empty())
{
d=q.front();
k=first[d]; // 注意!进去的是点
while(k!=-1) //扫描当前点的所有边(注意是双向的)
{
if(dis[v[k]]>dis[u[k]]+w[k])
{
dis[v[k]]=dis[u[k]]+w[k];
if(book[v[k]]!=1)
{
q.push(v[k]);
book[v[k]]=1;
}
}
k=next[k];
//printf("%d*\n",k);
/*for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
printf("\n");
for(int i=1;i<=n;i++)
{
printf("%d ",book[i]);
}
printf("\n");*/
}
book[d]=0;
q.pop();
}
printf("%d\n",dis[n]);
}
}
提交超时!!!
我再次DBUG了很长时间!!好气啊
错误就一处
那就是first的数组开大了
而且在初始化first初始化的也多了!!
我觉得这才多初始化2000次,应该不会超时吧!事实上超时
以后写代码的话能省就省,能优化一点就立即优化!
下面再上一下AC代码 就修改了两处
#include
#include
using namespace std;
int u[4005],v[4005],w[4005];
int first[1005],next[4005];
int dis[1005],book[1005];
#define inf 99999999
int main()
{
int t,n;
queue q;
while(scanf("%d%d",&t,&n)!=EOF)
{
int k,a,b,c,d;
for(int i=1; i<=n; i++) //first 初始化一下准备开始建图
{
first[i]=-1;
}
for(int i=1;i<=n;i++)
{
book[i]=0; //初始化 表示栈里面没有元素
dis[i]=inf;
}
dis[1]=0;
for(int i=1; i<=2*t; i+=2)
{
scanf("%d%d%d",&a,&b,&c);
u[i]=a,v[i]=b,w[i]=c;
u[i+1]=b,v[i+1]=a,w[i+1]=c;
}
/*for(int i=1;i<=2*t;i++)
{
printf("%d %d %d*\n",u[i],v[i],w[i]);
}*/
for(int i=1;i<=2*t;i++)
{
next[i]=first[u[i]];
first[u[i]]=i;
}
/*for(int i=1;i<=2*t;i++)
{
printf("[%2d] %2d %2d*.*\n",i,first[i],next[i]);
}*/
q.push(1);
book[1]=1;
while(!q.empty())
{
d=q.front();
k=first[d]; // 注意!进去的是点
while(k!=-1) //扫描当前点的所有边(注意是双向的)
{
if(dis[v[k]]>dis[u[k]]+w[k])
{
dis[v[k]]=dis[u[k]]+w[k];
if(book[v[k]]!=1)
{
q.push(v[k]);
book[v[k]]=1;
}
}
k=next[k];
//printf("%d*\n",k);
/*for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
printf("\n");
for(int i=1;i<=n;i++)
{
printf("%d ",book[i]);
}
printf("\n");*/
}
book[d]=0;
q.pop();
}
printf("%d\n",dis[n]);
}
}