今天回顾了经典的Dijstra算法,发现还是有些coding 地方没处理好,结果还弄了一会儿,这个算法按道理就是要一气呵成的,总结下遇到的问题。
MAXDIst不可避免,虽然这种设置会有缺陷,比如你不知道最大的距离会到多大,只能设置个看起来较大的数。。。
我已开始回想总是想不起来外层循环是干嘛。。。后来看了算法思想才知道,是和一般的循环有区别外层循环其实是逐个将除掉source以外的n-1个点加到一个集合里,这个集合表示所有已经算出最短距离的点击。因此出现了集合操作,但是教材的算法都是不断的去看visit变量来看是否加入,这种感觉挺别扭的,为啥原始不是涉及集合操作,集合的删除,插入等,从n-1个点击删除,插入到算出的点击。后来想想还有有原因的,因为要经常通过index来访问对应的dist,edge matrix,这些都是数组存储的,但是好像也可以啊,比如集合通过遍历访问,然后找到后如果可以获取他的index,那其实和不用集合没有本质区别。。。
注意题目是0-based 还是1-based index,这个一般不会有问题。
前面的初始化份三步,
1.先memset bool 数组 false,但原点为TRUE,因为一开始就加入点击了,距离不用定义,否则到后面可能误访问了原点的。
2.距离如果用-1表示的要先还原为MAXDIST,因为后面有个找min dist ,如果-1 当然设置if条件表达式也可以排除,后面dist update好像也是可以排除,这个可能可以出个考题,好吧自己再YY。。。
3.初始化dist为距离,除掉sourcei的 dist 其实这个赋值多少都不影响大局,因为后面根本不会访问到
主算法是外层一个for n-1次loop,因为加入了原点了。内层两次forloop,第一次算最小dist,包括index,因为后面
要把它加入集合,还有后面updatedist。然后后面for update dist。
貌似完成了,但是最需要当心的就是update的 时候 有一项出现了MinDIST 结果是否和预期的一样。还有就是找Min的时候
如果剩下的全是MAXDIST,怎么处理,所以这里我没考虑,于是出现了后面用Minj野值的情况,而且这里还发现了一个可以某些情况减少操作次数的case,
当remaining dist全都是MAXDIST时候,说明剩下的最短距离不会在更新了,因为找不到点可以到他们呢,也即他们分别是鼓励的点,所以可以直接break外层循环了,
不记得教材有没有这么做。
最后附上代码,好像可以优化成不需要MAXDIST的,待会儿试试
#include <iostream>
using namespace std;
#define MaxDist 100000
void dijstra(int **Edge, int*Dist, int n, int sourcei)
{
//initilal bool
bool *HasGotShortest=new bool[n];//不要用new,fawks大神说过了的,另外new也不用memset,因为堆的默认0
memset(HasGotShortest,0,n*sizeof(bool));
HasGotShortest[sourcei]=true;
//update Edge as Max, if -1, because need to compare
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(Edge[i][j]==-1)
Edge[i][j]=MaxDist;//这个还是有必要的,感觉后面的简直就是作死,完全没有这么做的。
//initial dist
for(int i=0;i<n;i++)
{
if(i!=sourcei)//不判断没事儿,因为Edge[sourcei][sourcei]=0,Edge如果是堆或者全局变量的默认也是0,再说Dist[sourcei]就算是野值也不影响,因为后面不会用到的,用visit把他挡开了
Dist[i]=Edge[sourcei][i];
}
int min, minj;
for(int i=1;i<n;i++)// add one vertex per loop, but not know which vertex这里一定是n-1轮,因为前面sourcei已经加入最短路径了,对应值为0
{
min=MaxDist;minj=-1;//循环变量初始化,index默认为-1吧
for(int j=0;j<n;j++)//get reaminging sets' min dist, and minj
{
if(!HasGotShortest[j])
{
if(min>Dist[j])
{
min=Dist[j];
minj=j;
}
}
}
if(min==MaxDist)//remaining are all MaxDist, no add, not update,也可以判断minj==-1,总之true的话,后面都是不可达结点,不连通了,直接返回,否则访问visited数组后面会出错了,而不是提高效率的问题了
break;
HasGotShortest[minj]=true;//add new vertex, that is current remaining minimum dist
for(int j=0;j<n;j++)//update remaining sets' dist, according to just addde vertex
{
if(!HasGotShortest[j])
{
if(Dist[j]>Dist[minj]+Edge[minj][j])//Dist[minj]肯定不是MAX,另外两个分别是MAX和>0值的四种情况都是正确的
Dist[j]=Dist[minj]+Edge[minj][j];
}
}
}
delete []HasGotShortest;
}
int main()
{
int n;
int casei=1;
while(cin>>n)
{
int sourcei,desti;
int **Edge=new int*[n];
for(int i=0;i<n;i++)
Edge[i]=new int[n];
int *Dist=new int[n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>Edge[i][j];
cin>>sourcei>>desti;
dijstra(Edge,Dist,n,sourcei-1);
cout<<"Case "<<casei<<endl;
casei++;
cout<<Dist[desti-1]<<endl;
delete []Dist;
for(int i=0;i<n;i++)
delete []Edge[i];
delete[] Edge;
}
return 0;
}
果然经过调试,发现确实可以不用MaxDist,这样可以不用知道最大的距离为多少,只是找mindist,和update 的逻辑稍微纠结一点,但还是可以实现的。
void dijstra(int **Edge, int*Dist, int n, int sourcei)
{
//initilal bool
bool *HasGotShortest=new bool[n];
memset(HasGotShortest,0,n*sizeof(bool));
HasGotShortest[sourcei]=true;
//update Edge as Max, if -1, because need to compare
/*
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(Edge[i][j]==-1)
Edge[i][j]=MaxDist;
*/
//initial dist
for(int i=0;i<n;i++)
{
if(i!=sourcei)
Dist[i]=Edge[sourcei][i];
}
int min, minj;
for(int i=1;i<n;i++)// add one vertex per loop, but not know which vertex
{
min=-1;bool firstdist=true;
for(int j=0;j<n;j++)//get reaminging sets' min dist, and minj
{
if(!HasGotShortest[j])
{
if(Dist[j]>0&&(firstdist||min>Dist[j]))// if exsit Dist[j] >0, assign first positve dist to min
{
firstdist=false;
min=Dist[j];
minj=j;
}
}
}
if(min==-1)//remaining are all MaxDist, no add, not update
break;
HasGotShortest[minj]=true;//add new vertex, that is current remaining minimum dist
for(int j=0;j<n;j++)//update remaining sets' dist, according to just addde vertex
{
if(!HasGotShortest[j])
{
if(Dist[j]==-1 && Edge[minj][j]!=-1)
{
Dist[j]=Dist[minj]+Edge[minj][j];
}
if(Dist[j]!=-1&&Edge[minj][j]!=-1)
{
if(Dist[j]>Dist[minj]+Edge[minj][j])
Dist[j]=Dist[minj]+Edge[minj][j];
}
//remaining two case not update Dist[j]
}
}
}
delete []HasGotShortest;
}