九度oj题目1008:最短路径问题
题目描述:
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
- 输入:
-
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。 (1<n<=1000, 0<m<100000, s != t)
- 输出:
-
输出 一行有两个数, 最短距离及其花费。
- 样例输入:
-
3 2 1 2 5 6 2 3 4 5 1 3 0 0
- 样例输出:
-
9 11
通过这道题复习了一下迪杰特斯拉算法,算法的精髓在于每回找一个距离集合最近的点加到集合中,直到不能加入更多的点为止
代码如下:1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #define MAX 999999999 7 #define N 1005 8 #define M 100005 9 10 struct Way { 11 int distance; 12 int cost; 13 }; 14 15 Way map[N][N];//邻接矩阵 16 Way dis[N];//起点到各个点的距离表 17 int flag[N];//判别某点是否在已包括点的集合中 18 19 void dijkstra(int start, int end,int n) { 20 memset(flag,0,sizeof(int)*N); 21 //初始化距离 22 for(int i = 1; i <= n; i++) { 23 dis[i] = map[start][i]; 24 } 25 dis[start].distance = 0;//该点到自己的距离为0 26 dis[start].cost = 0;//到自己的花费为0 27 flag[start] = 1;//把自己包括到可以到达的点中 28 29 for(int i = 1; i < n; i++) { 30 //总共需要加入n-1个点,所以循环n-1次 31 int index = 0; 32 int min = MAX; 33 for(int j = 1; j <= n; j++) { 34 if(flag[j] == 0 && dis[j].distance < min) { 35 index = j; 36 min = dis[j].distance; 37 } 38 } 39 //find the min index 40 flag[index] = 1; 41 42 for(int j = 1; j <= n; j++) { 43 if(flag[j] == 0 && (dis[index].distance + map[index][j].distance < dis[j].distance)) { 44 dis[j].distance = dis[index].distance + map[index][j].distance; 45 dis[j].cost = dis[index].cost + map[index][j].cost; 46 } 47 else if(flag[j] == 0 && (dis[index].distance + map[index][j].distance == dis[j].distance)){ 48 if(dis[j].cost > dis[index].cost + map[index][j].cost) { 49 dis[j].cost = dis[index].cost + map[index][j].cost; 50 } 51 } 52 } 53 } 54 55 56 } 57 58 int main(int argc, char const *argv[]) 59 { 60 int n,m; 61 int source, des; 62 scanf("%d %d",&n,&m); 63 while(n != 0 && m != 0) { 64 for(int i = 1; i <= n; i++) { 65 for(int j = 1; j <= n; j++) { 66 map[i][j].distance = MAX; 67 map[i][j].cost = MAX; 68 } 69 } 70 int pointA,pointB,disc,cost; 71 for(int i = 0; i < m; i++) { 72 scanf("%d %d %d %d",&pointA,&pointB,&disc,&cost); 73 map[pointA][pointB].distance = disc; 74 map[pointB][pointA].distance = disc; 75 map[pointA][pointB].cost = cost; 76 map[pointB][pointA].cost = cost; 77 } 78 scanf("%d %d",&source,&des); 79 80 dijkstra(source,des,n); 81 printf("%d %d\n",dis[des].distance,dis[des].cost); 82 scanf("%d %d",&n,&m); 83 } 84 return 0; 85 }
最近尝试了一下用优先队列来解决问题,感觉写得很别扭,不过还是写出来了,速度提高不少,代码如下
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 #include <queue> 5 6 #define MAX_V 1002 7 #define inf 999999999 8 using namespace std; 9 10 struct Edge 11 { 12 public: 13 int to; 14 int dis; 15 int cost; 16 Edge(int to, int dis,int cost) { 17 this->to = to; 18 this->dis = dis; 19 this->cost = cost; 20 } 21 }; 22 23 struct cmp{ 24 bool operator()(const Edge &a,const Edge &b){ 25 if(a.dis == b.dis) { 26 return a.cost - b.cost; 27 } 28 else { 29 return a.dis - b.dis; 30 } 31 } 32 }; 33 typedef pair<int , int> P;//first dis, sencond cost 34 P dist[MAX_V]; 35 vector<Edge> G[MAX_V]; 36 priority_queue<Edge, vector<Edge>, cmp> que; 37 38 int main(int argc, char const *argv[]) 39 { 40 int n,m; 41 int source, des; 42 freopen("input.txt","r",stdin); 43 while(scanf("%d %d",&n,&m) != EOF && (n != 0 && m != 0)) { 44 for(int i = 0; i <= n; i++) { 45 G[i].clear(); 46 } 47 for(int i = 0; i < m; i++) { 48 int a, b, disc, cost; 49 scanf("%d %d %d %d",&a,&b,&disc,&cost); 50 G[a].push_back(Edge(b,disc,cost)); 51 G[b].push_back(Edge(a,disc,cost)); 52 } 53 scanf("%d %d",&source,&des); 54 fill(dist,dist+n+1,P(inf,inf)); 55 dist[source] = P(0,0); 56 que.push(Edge(source,0,0)); 57 58 while(!que.empty()) { 59 Edge t = que.top(); que.pop(); 60 int v = t.to, d = t.dis, c = t.cost; 61 if(dist[v].first < d) { 62 continue; 63 } 64 for(int i = 0; i < G[v].size(); i++) { 65 Edge &e = G[v][i]; 66 int d2 = d + e.dis; 67 int c2 = c + e.cost; 68 69 if(dist[e.to].first > d2 || (dist[e.to].first == d2 && dist[e.to].second > c2)) { 70 dist[e.to] = P(d2,c2); 71 que.push(Edge(e.to,d2,c2)); 72 } 73 } 74 } 75 printf("%d %d\n",dist[des].first,dist[des].second); 76 77 } 78 return 0; 79 }