最短路径问题—九度OJ1008 (2010年浙江大学研究生机试真题)

题目1008:最短路径问题

时间限制:1 秒

内存限制:32 兆

特殊判题:

提交:3302

解决:988

题目描述:
给你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
来源:
2010年浙江大学计算机及软件工程研究生机试真题
思路:这题目和普通的最短距离,不一样的地方就是费用,如果到两条到达终点的路径,距离不同,则求最短路同时更新费用,如果有多条到终点距离相同,则应考虑怎么更新费用,整体难度不大.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;
const int maxn = 1010;
const int maxm = 100010;
const int INF = 0x7fffffff;
int gn, gm;
struct info {
    int d;
    int p;
};
info g[maxn][maxn];
bool vis[maxn];
int dis[maxn];
int price[maxn];

void dijkstra(const int s, const int t) {
    int i, j;
    for(i = 1; i <= gn; i++) {
        dis[i] = INF;
        price[i] = INF;
    }
    dis[s] = 0;
    price[s] = 0;
    memset(vis, false, sizeof(vis));
    for(i = 1; i <= gn; i++) {
        int mark = -1, mindis = INF;
        for(j = 1; j <= gn; j++) {
            if(!vis[j] && dis[j] < mindis) {
                mindis = dis[j];
                mark = j;
            }
        }
        vis[mark] = true;
        for(j = 1; j <= gn; j++) {
            if(!vis[j] && dis[mark] <= dis[j] - g[mark][j].d && g[mark][j].d != INF) {//不存在的边,不会跟新.
                if(dis[mark] + g[mark][j].d < dis[j]) {//防止无穷大的数据相加时产生溢出.
                    dis[j] = dis[mark] + g[mark][j].d;
                    price[j] = price[mark] + g[mark][j].p;

                }
                else {
                    price[j] = min(price[j], price[mark]+g[mark][j].p);
                }
            }
        }
    }
    printf("%d %d\n", dis[t], price[t]);
}

void init() {//初始化.不存在的边为无穷大.
    int i, j;
    for(i = 1; i <= gn; i++) {
        for(j = 1; j <= gn; j++) {
            if(i == j) continue;
            else {
                g[i][j].d = INF;
                g[i][j].p = INF;
            }
        }
    }
}

int main()
{
    int x, y, d, p;
    int i, s, t;
    while(scanf("%d%d", &gn, &gm) != EOF) {
        if(gn == 0 && gm == 0) break;
        init();
        for(i = 0; i < gm; i++) {
            scanf("%d%d%d%d", &x, &y, &d, &p);
            g[x][y].d = d;
            g[x][y].p = p;
            g[y][x].d = d;
            g[y][x].p = p;
        }
        scanf("%d%d", &s, &t);
        dijkstra(s, t);
    }
    return 0;
}
//第一个程序没有考虑重边的情况所有在HDU3790上WA。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;
const int maxn = 1110;
const int INF = 0x7fffffff;
int gn, gm;

struct info {
    int d;
    int p;
};

info g[maxn][maxn];
bool vis[maxn];
int dis[maxn];
int price[maxn];

void dijkstra(const int s, const int t) {
    int i, j;
    for(i = 1; i <= gn; i++) {
        dis[i] = INF;
        price[i] = INF;
    }
    dis[s] = 0;
    price[s] = 0;
    memset(vis, false, sizeof(vis));
    for(i = 1; i <= gn; i++) {
        int mark = -1, mindis = INF;
        for(j = 1; j <= gn; j++) {
            if(!vis[j] && dis[j] < mindis) {
                mindis = dis[j];
                mark = j;
            }
        }
        vis[mark] = true;
        for(j = 1; j <= gn; j++) {
            if(!vis[j] && g[mark][j].d != INF && dis[mark] != INF && dis[mark] <= dis[j] - g[mark][j].d ) {//不存在的边,不会跟新.
                if(dis[mark] < dis[j] - g[mark][j].d) {//防止无穷大的数据相加时产生溢出.
                    dis[j] = dis[mark] + g[mark][j].d;
                    price[j] = price[mark] + g[mark][j].p;
                }
                else {
                    price[j] = min(price[j], price[mark]+g[mark][j].p);
                }
            }
        }
    }
    printf("%d %d\n", dis[t], price[t]);
}

void init() {//初始化.不存在的边为无穷大.
    int i, j;
    for(i = 1; i <= gn; i++) {
        for(j = 1; j <= gn; j++) {//因为i==j时候,自己不会更新自己。
            g[i][j].d = INF;
            g[i][j].p = INF;
        }
    }
}

int main()
{
    int x, y, d, p;
    int i, s, t;
    while(scanf("%d%d", &gn, &gm) != EOF) {
        if(gn == 0 && gm == 0) break;
        init();
        for(i = 0; i < gm; i++) {
            scanf("%d%d%d%d", &x, &y, &d, &p);
            if(g[x][y].d == INF){
                g[x][y].d = d;
                g[x][y].p = p;
                g[y][x].d = d;
                g[y][x].p = p;
            }
            else {
                if(g[x][y].d > d) {
                    g[x][y].d = d;
                    g[y][x].d = d;
                    g[x][y].p = p;
                    g[y][x].p = p;
                }
                if(g[x][y].d == d) {
                    g[x][y].p = min(g[x][y].p, p);
                    g[y][x].p = min(g[y][x].p, p);
                }
            }
        }
        scanf("%d%d", &s, &t);
        dijkstra(s, t);
    }
    return 0;
}
/**
7 9
1 2 2 2
1 3 4 5
1 4 3 1
1 5 5 2
2 7 9 7
3 7 5 6
4 7 7 2
5 6 2 2
6 7 2 2
1 7

9 6
**/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值