Dijkstra算法优化

最近在做浙江大学复试机试题中遇见的问题一下为链接https://www.nowcoder.com/practice/e372b623d0874ce2915c663d881a3ff2?tpId=63&tqId=29599&tPage=2&rp=2&ru=/ta/zju-kaoyan
问题描述:给你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)

输出描述:

输出 一行有两个数, 最短距离及其花费。

例子:

8 12
1 2 2 2
1 4 6 2
1 6 9 2
2 4 1 2
2 3 30 2
3 8 5 2
4 5 2 2
6 5 3 2
6 7 24 2
5 7 7 2
5 3 8 2
7 8 21 2
1 8

输出

18 10

普通算法:o(n^2)

#include<iostream>
#define N 1001
#define MAX 10000000
int cost[N][N];//Adjacency table
int dis[N][N];
int d[N];//shortest length
int c[N];
bool mark[N];
 
using namespace std;
void init(int n) {
    for (int i = 1; i <= n; i++) {
        d[i] = MAX; c[i] = MAX; mark[i]=false;
    }
    //undirect graph
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == j) {
                dis[i][j] = 0; cost[i][j] = 0;
            }
            else {
                dis[i][j] = MAX; dis[j][i] = MAX;
                cost[i][j] = MAX; cost[j][i] = MAX;
            }
        }
    }
}
int main() {
    int n, m;
    while (cin >> n >> m && n > 0) {
        init(n);
        while (m--) {
            //d:distance p:price
            int a, b, d, p; cin >> a >> b >> d >> p;
            if(dis[a][b]>d){
                dis[a][b] = d; dis[b][a] = d;
                cost[a][b] = p; cost[b][a] = p;
            }
            else if(dis[a][b]==d&&cost[a][b]>p){
                cost[a][b]=p;cost[b][a]=p;
            }
        }
        int begin, end; cin >> begin >> end;
        //inital begin vertex
        d[begin] = 0; c[begin] = 0; mark[begin] = true;
        
        int newS = begin;
        //every first loop will add one vertex to array of S
        //so we must have n times loop
        for (int i = 1; i <= n; i++) {
            //update the array of d and c
            for (int j = 1; j <= n; j++) {
              if (mark[j])continue;
                int nd = dis[newS][j];
                int nc = cost[newS][j];
               
                if (nd + d[newS] < d[j]) {
                    d[j] = nd + d[newS]; c[j] = nc + c[newS];
                }
                else if (nd + d[newS] == d[j] && nc + c[newS] < c[j])c[j] = nc + c[newS];
            }
            int min = MAX;
            //update newS
            for (int j = 1; j <= n; j++) {
            	//except the add vertex and the unreached vertex
                if (mark[j])continue;
                if (d[j] == MAX)continue;
                //pic the minist distance
                if (d[j] < min) {
                    min = d[j]; newS = j;
                }
            }
            //add the new vertex
            mark[newS] = true;
        }
        cout << d[end] << " " << c[end] << endl;
    }
}

其实我们在第一次循环中每一个点都要去和其他所有点进行遍历,但是我们中间结果所产生的路径似乎没有被存储

于是我们思考用优先队列q来存储中间路径

于是我们可以看到每一次遍历优先队列里都会包含上一个节点所包含的路径,由于优先队列是小根堆,那么top元素即为我们所求的元素。因此时间复杂度变为(e+n)loge

#include<iostream>
#include<queue>
#include<vector>
#define N 1001
#define MAX 10000000
int cost[N][N];//Adjacency table
int dis[N][N];
int d[N];//shortest length
int c[N];
bool mark[N];

using namespace std;
//use small heap compare
//if d[a]!=d[b] return small heap of distance
//else return small heap of cost
struct cmp
{
	bool operator()(int a, int b) {
		if (d[a] != d[b])return d[a] > d[b];
		else return c[a] > c[b];
	}
};
void init(int n) {
	for (int i = 1; i <= n; i++) {
		d[i] = MAX; c[i] = MAX; mark[i] = false;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (i == j) {
				dis[i][j] = 0; cost[i][j] = 0;
			}
			else {
				dis[i][j] = MAX; dis[j][i] = MAX;
				cost[i][j] = MAX; cost[j][i] = MAX;
			}
		}
	}
}
int main() {
	int n, m;
	while (cin >> n >> m && n > 0) {
		init(n);
		while (m--) {
			//d:distance p:price
			int a, b, d, p; cin >> a >> b >> d >> p;
			if (dis[a][b] > d) {
				dis[a][b] = d; dis[b][a] = d;
				cost[a][b] = p; cost[b][a] = p;
			}
			else if (dis[a][b] == d && cost[a][b] > p) {
				cost[a][b] = p; cost[b][a] = p;
			}
		}
		int begin, end; cin >> begin >> end;
		//inital begin vertex
		d[begin] = 0; c[begin] = 0;
		priority_queue<int, vector<int>, cmp> q;
		q.push(begin);
		while (!q.empty()) {
			int current = q.top();
			q.pop();
			if (mark[current])continue;
			mark[current] = true;
            //if the vertex not vist
            //then loop judge the distance of d
			for(int i=1;i<=n;i++)if (!mark[i])
			{
				//if current d add direct d less than d of direct
				if (d[current] + dis[current][i] < d[i]) {
					d[i] = d[current] + dis[current][i];
					c[i] = c[current] + cost[current][i];
					q.push(i);
				}
			}
		}
		cout << d[end] << " " << c[end] << endl;
	}
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值