最近在做浙江大学复试机试题中遇见的问题一下为链接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;
}
}