1 View Code 2 3 /* 4 输入的文本中弧的起点,终点是按字典顺序排列的,所以算法对此作了相应简化 5 即使不是按照字典顺序,也可以轻易的排列成字典顺序,这里不作考虑 6 d:\mydir\1.txt网络地址:http://202.113.29.10/class/ds12/hw12p.txt 记录顶点信息 7 d:\mydir\2.txt网络地址:http://202.113.29.10/class/ds12/hw12r.txt 记录弧信息 8 */ 9 #include<iostream> 10 #include<fstream> 11 #include<vector> 12 #include<queue> //FIFO,不提供迭代器和下标访问 13 #include<string> 14 #include<iomanip> 15 using namespace std; 16 17 struct vertex 18 { 19 int num; 20 double x,y; 21 }; 22 struct arc 23 { 24 int head,tail; 25 double length; 26 }; 27 struct adjacency_matrix 28 { 29 bool status; //邻接标志,邻接为true,不邻接为false 30 int posi; //元素对应的弧在arc类中的a对象中的位置 31 double length; //相邻两点间距,不相邻则为-1 32 double shortest; //两点间最短路径,用100000表示infinite 33 vector<int> path; //记录最短路径经过的顶点 34 }; 35 inline bool min(double &a,double b) 36 { 37 if(a>b) 38 {a=b;return true;} 39 else 40 return false; 41 }; 42 class graph 43 { 44 private: 45 vector<vertex> v; 46 vector<arc> a; 47 vector<adjacency_matrix> am; 48 int vertex_num; 49 int arc_num; 50 public: 51 graph(); 52 int pos(int a,int b); 53 void Reduct(); 54 void Dijkstra(int init); 55 void Dijkstra_Shortest_Distance(); 56 void Floyd_Shortest_Distance(); 57 void Dijkstra_Print(); 58 void Floyd_Print(); 59 }; 60 graph::graph() 61 { 62 int i,j,pos; 63 double x,y; 64 string s; 65 vertex temp; 66 arc buf; 67 adjacency_matrix store; 68 //--读入点信息:下标0的元素无意义,下标1-vertex_num的元素顺序记录点信息-- 69 fstream point("d:\\mydir\\1.txt"); 70 if(point.fail()) 71 {cerr<<"open failed!"<<endl;return;} 72 getline(point,s,'\n'); 73 temp.num=0;temp.x=temp.y=0; 74 v.push_back(temp); 75 while(!point.eof()) 76 { 77 point>>temp.num>>temp.x>>temp.y; 78 v.push_back(temp); 79 } 80 vertex_num=v.size()-1; 81 point.close(); 82 //--读入弧信息:下标0的元素无意义,下标1-arc_num的元素顺序记录弧信息-- 83 fstream line("d:\\mydir\\2.txt"); 84 if(line.fail()) 85 {cerr<<"open failed!"<<endl;return;} 86 getline(line,s,'\n'); 87 buf.head=buf.tail=0;buf.length=0; 88 a.push_back(buf); 89 while(!line.eof()) 90 { 91 line>>buf.head>>buf.tail; 92 x=v[buf.head].x-v[buf.tail].x; 93 y=v[buf.head].y-v[buf.tail].y; 94 buf.length=sqrt(x*x+y*y); 95 a.push_back(buf); 96 } 97 arc_num=a.size()-1; 98 line.close(); 99 //--创建邻接矩阵:下标0的元素无意义,下标1-vertex_num*vertex_num的元素顺序记录相邻信息-- 100 //------初始邻接矩阵,最短路径设置为100000,任意两点间距为-1---------------------- 101 store.status=false;store.posi=-1;store.length=-1;store.shortest=100000;store.path.push_back(0); 102 am.push_back(store); 103 for(i=1;i<=vertex_num;++i) 104 for(j=1;j<=vertex_num;++j) 105 { 106 store.path.clear(); 107 store.path.push_back(i);store.path.push_back(j); 108 am.push_back(store); 109 } 110 //------依据弧信息改写邻接矩阵,将相邻点的最短路径暂时设定为两点间距---------------- 111 for(i=1;i<=arc_num;++i) 112 { 113 //------给邻接矩阵赋值------------------- 114 pos=(a[i].head-1)*vertex_num+a[i].tail; 115 am[pos].status=true;am[pos].posi=i;am[pos].length=am[pos].shortest=a[i].length; 116 } 117 //------顶点自身到自身的最短距离设定为0------ 118 for(i=1;i<=vertex_num;++i) 119 am[(i-1)*vertex_num+i].shortest=0; 120 //--测试读入结果-- 121 //--将读入的信息存储到d:\mydir\read_text.txt中-------------------- 122 fstream read_test; 123 read_test.open("d:\\mydir\\read_test.txt",ios::out|ios::trunc); 124 if(read_test.fail()) 125 { 126 cerr<<"read_test.txt open failed ! "<<endl; 127 system("pause"); 128 } 129 //--测试点信息-- 130 read_test<<"the number of vertex:"<<vertex_num<<endl; 131 for(i=1;i<=vertex_num;++i) 132 { 133 read_test<<setiosflags(ios::left); 134 read_test<<setw(4)<<v[i].num<<setw(4)<<v[i].x<<setw(4)<<v[i].y<<endl; 135 } 136 //--测试弧信息-- 137 read_test<<"the number of arc:"<<arc_num<<endl; 138 for(i=1;i<=arc_num;++i) 139 { 140 read_test<<setiosflags(ios::left); 141 read_test<<setw(4)<<a[i].head<<setw(4)<<a[i].tail; 142 read_test<<setw(10)<<a[i].length<<endl; 143 } 144 //--测试邻接矩阵信息-- 145 read_test<<"the adjacency matrix:"<<endl; 146 for(i=1;i<=vertex_num*vertex_num;++i) 147 { 148 if(am[i].status==false) 149 read_test<<"F "; 150 else 151 { 152 read_test<<"T "; 153 read_test<<setiosflags(ios::left); 154 read_test<<setw(4)<<am[i].posi; 155 read_test<<setw(4)<<a[am[i].posi].head<<setw(4)<<a[am[i].posi].tail; 156 read_test<<am[i].length<<endl; 157 } 158 if(i%vertex_num==0) 159 read_test<<endl; 160 } 161 } 162 int graph::pos(int a,int b) 163 { 164 return (a-1)*vertex_num+b; 165 } 166 //--Reduct函数:还原邻接矩阵到初始化状态-- 167 void graph::Reduct() 168 { 169 int i,j,k,temp; 170 for(i=1;i<=vertex_num;++i) 171 for(j=1;j<=vertex_num;++j) 172 { 173 k=pos(i,j); 174 am[k].status=false;am[k].shortest=100000; 175 am[k].path.clear();am[k].path.push_back(i);am[k].path.push_back(j); 176 } 177 //------依据弧信息改写邻接矩阵,将相邻点的最短路径暂时设定为两点间距---------------- 178 for(i=1;i<=arc_num;++i) 179 { 180 //------给邻接矩阵赋值------------------- 181 temp=(a[i].head-1)*vertex_num+a[i].tail; 182 am[temp].status=true;am[temp].posi=i;am[temp].length=am[temp].shortest=a[i].length; 183 } 184 //------顶点自身到自身的最短距离设定为0------ 185 for(i=1;i<=vertex_num;++i) 186 am[(i-1)*vertex_num+i].shortest=0; 187 }; 188 //--Dijkstra函数:用Dijkstra算法返回第init个点到其他所有点的最小路径-- 189 void graph::Dijkstra(int i) 190 { 191 //--初始化-- 192 //--l为loop缩写,是循环变量,对应邻接矩阵am-- 193 //--i=init记录源点;j记录正在计算的终点;k为路上经过的点-- 194 //--q对应"已经读取"集合S,初始化只含一个元素init-- 195 //--b_push,b_pop分别对应顶点压入过队列和推出过队列,初始化为false-- 196 bool b; 197 int j,k,l; 198 queue<int> q; 199 vector<bool> b_push,b_pop; 200 q.push(i); 201 for(l=0;l<=vertex_num;++l) 202 { 203 b_push.push_back(false); 204 b_pop.push_back(false); 205 } 206 b_push[i]=true; 207 //--求最短路径-- 208 //--当队列非空时,从队列的头部推出一个顶点init----------------------------------- 209 //--查找与init相邻且未压入过队列的顶点,使之入队列-------------------------------- 210 //--查找与init相邻且未被推出队列的顶点,通过比较重定义它们的最短距离----------------- 211 while(!q.empty()) 212 { 213 //--推出队列头部的一个顶点,并在b_pop中标记-- 214 k=q.front();q.pop();b_pop[k]=true; 215 for(l=pos(k,1);l<=pos(k+1,0);++l) 216 { 217 j=l-(k-1)*vertex_num; 218 //--查找与之相邻且未压入过队列的顶点,将它们压入队列-- 219 if(am[l].status==true&&b_push[j]==false) 220 { 221 //--压入队列,并在b_push中标记----- 222 q.push(j);b_push[j]=true; 223 } 224 //--查找与之相邻且未推出过队列的顶点,并按下列算法重定义最短距离,同时重定义最短路径-- 225 //--distance[i][j] = min ( distance[i][j], distance[i][k]+distance[k][j] )-- 226 if(am[l].status==true&&b_pop[j]==false) 227 { 228 b=min(am[pos(i,j)].shortest,am[pos(i,k)].shortest+am[pos(k,j)].shortest); 229 if(b==true) 230 { 231 am[pos(i,j)].path.clear(); 232 for(unsigned m=0;m<am[pos(i,k)].path.size();++m) 233 am[pos(i,j)].path.push_back(am[pos(i,k)].path[m]); 234 am[pos(i,j)].path.push_back(j); 235 } 236 } 237 } 238 } 239 /* 240 //--测试Dijkstra算法的结果--------- 241 for(l=0;l<vertex_num;++l) 242 { 243 cout<<" ("<<i<<","<<l<<") "<<am[pos(i,l)].shortest<<" "; 244 if((i+1)%5==0) 245 cout<<endl; 246 } 247 */ 248 }; 249 //--起点、终点、最短距离、中间依次经过的路口编号-- 250 void graph::Dijkstra_Shortest_Distance() 251 { 252 for(int i=1;i<=vertex_num;++i) 253 Dijkstra(i); 254 } 255 //--Floyd_Shortest_Distance函数:用Floyd算法返回所有点之间的最小路径-- 256 void graph::Floyd_Shortest_Distance() 257 { 258 bool b; 259 unsigned l; 260 int i,j,k; 261 for(k=1;k<=vertex_num;++k) 262 for(i=1;i<=vertex_num;++i) 263 for(j=1;j<=vertex_num;++j) 264 { 265 //--用以下算法分别对最短距离和路径赋值---------- 266 //--if(dist[i][k]+dist[k][j]<dist[i][j]) 267 //--dist[i][j]=dist[i][k]+dist[k][j]; 268 //--path[i][j]=path[i][k]+path[k][j]; 269 b=min(am[pos(i,j)].shortest,am[pos(i,k)].shortest+am[pos(k,j)].shortest); 270 if(b==true) 271 { 272 am[pos(i,j)].path.clear(); 273 for(l=0;l<am[pos(i,k)].path.size()-1;++l) 274 am[pos(i,j)].path.push_back(am[pos(i,k)].path[l]); 275 for(l=0;l<am[pos(k,j)].path.size();++l) 276 am[pos(i,j)].path.push_back(am[pos(k,j)].path[l]); 277 } 278 } 279 }; 280 void graph::Dijkstra_Print() 281 { 282 //--创建文件,文件名为:Dijkstra_shortest_distance.txt,位置D盘----- 283 fstream shortest_distance; 284 shortest_distance.open("d:\\mydir\\Dijkstra_shortest_distance_and_path.txt",ios::out|ios::trunc); 285 if(shortest_distance.fail()) 286 {cerr<<"Dijkstra open failed!"<<endl;system("pause");} 287 //--用插入器 << 将数据写入文件--- 288 for(int i=1;i<=vertex_num;++i) 289 { 290 for(int j=1;j<=vertex_num;++j) 291 { 292 shortest_distance<<setiosflags(ios::left); 293 shortest_distance<<" ("<<setw(3)<<i<<","<<setw(3)<<j<<") "; 294 if(am[pos(i,j)].shortest!=100000) 295 { 296 shortest_distance<<setw(10)<<am[pos(i,j)].shortest<<" "; 297 for(int k=0;k!=am[pos(i,j)].path.size();++k) 298 shortest_distance<<setw(3)<<am[pos(i,j)].path[k]<<" "; 299 } 300 else 301 { 302 shortest_distance<<setw(11)<<"Infinite"; 303 shortest_distance<<"no path"; 304 } 305 shortest_distance<<endl; 306 } 307 } 308 } 309 void graph::Floyd_Print() 310 { 311 //--创建文件,文件名为:Floyd_shortest_distance.txt,位置D盘----- 312 fstream shortest_distance; 313 shortest_distance.open("d:\\mydir\\Floyd_shortest_distance_and_path.txt",ios::out|ios::trunc); 314 if(shortest_distance.fail()) 315 {cerr<<"Floyd open failed!"<<endl;system("pause");} 316 //--用插入器 << 将数据写入文件--- 317 for(int i=1;i<=vertex_num;++i) 318 { 319 for(int j=1;j<=vertex_num;++j) 320 { 321 shortest_distance<<setiosflags(ios::left); 322 shortest_distance<<" ("<<setw(3)<<i<<","<<setw(3)<<j<<") "; 323 if(am[pos(i,j)].shortest!=100000) 324 { 325 shortest_distance<<setw(10)<<am[pos(i,j)].shortest<<" "; 326 for(int k=0;k!=am[pos(i,j)].path.size();++k) 327 shortest_distance<<setw(3)<<am[pos(i,j)].path[k]<<" "; 328 } 329 else 330 { 331 shortest_distance<<setw(11)<<"Infinite"; 332 shortest_distance<<"no path"; 333 } 334 shortest_distance<<endl; 335 } 336 } 337 }; 338 int main() 339 { 340 graph g; 341 g.Dijkstra_Shortest_Distance(); 342 g.Dijkstra_Print(); 343 g.Reduct(); 344 g.Floyd_Shortest_Distance(); 345 g.Floyd_Print(); 346 system("pause"); 347 return 0; 348 }
参考资料:
Dijkstra算法为单源点最短路径算法: 图文示例:http://zh.wikipedia.org/zh-cn/Dijkstra%E7%AE%97%E6%B3%95
编程实例:http://www.nocow.cn/index.php/Dijkstra%E7%AE%97%E6%B3%95
Floyd算法为全源点最短路径算法: 图文示例:http://www.cnblogs.com/pelephone/articles/floyd-algorithm.html
编程实例:http://www.cnblogs.com/hackerain/archive/2010/12/05/2130431.html
2012-06-03