数据结构|最短路径

畅通工程续

Problem Description
某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。

现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

Input
本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

Output
对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.

Sample Input

3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2

Sample Output

2
-1

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<climits>

using namespace std;

const int MAXN=200;
const int INF=INT_MAX;//无穷设为很大的数

struct Edge{
    int to;//终点
    int length;//长度
    Edge(int t,int l):to(t),length(l){}
};

struct Point{
    int number;//点的编号
    int distance;//源点到该点的距离
    Point(int n,int d):number(n),distance(d){}
    bool operator<(const Point& p) const{
        return distance>p.distance;//距离小的优先级高(优先队列本身优先输出存储中的最大值)
    }
};

vector<Edge> graph[MAXN];//邻接表实现的图
int dis[MAXN];//源点到各点的距离

void Dijkstra(int s){
    priority_queue<Point> myPriorityQueue;
    dis[s]=0;
    myPriorityQueue.push(Point(s,dis[s]));
    while(!myPriorityQueue.empty()){
        int u=myPriorityQueue.top().number;//取优先队列中离源点最近的点
        myPriorityQueue.pop();
        for(int i=0;i<graph[u].size();++i){
            int v=graph[u][i].to;
            int d=graph[u][i].length;
            if(dis[v]>dis[u]+d){
                dis[v] =dis[u]+d;
                myPriorityQueue.push(Point(v,dis[v]));
            }
        }
    }
    return;
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(graph,0,sizeof(graph));//图初始化
        fill(dis,dis+n,INF);//距离初始化为无穷
        while(m--){
            int from,to,length;
            scanf("%d%d%d",&from,&to,&length);
            graph[from].push_back(Edge(to,length));
            graph[to].push_back(Edge(from,length));
        }
        int s,t;
        scanf("%d%d",&s,&t);
        Dijkstra(s);
        if(dis[t]==INF){//终点不可达
            dis[t]=-1;
        }
        printf("%d\n",dis[t]);
    }
    return 0;
}

最短路径问题

描述
给你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)
输出描述:
输出 一行有两个数, 最短距离及其花费。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<climits>

using namespace std;

const int MAXN=1001;
const int INF=INT_MAX;//无穷大设为很大的数

struct Edge{
    int to;//终点
    int length;//长度
    int price;//花费
    Edge(int t,int l,int p):to(t),length(l),price(p){}//初始化
};

struct Point{
    int number;//点的编号
    int distance;//源点到该点的距离
    Point(int n,int d):number(n),distance(d){}
    bool operator<(const Point& p)const{
        return distance>p.distance;//距离小的优先级高
    }
};

vector<Edge> graph[MAXN];//邻接表实现的图
int dis[MAXN];//源点到各点的距离
int cost[MAXN];//记录花费

void Dijkstra(int s){
    priority_queue<Point> myPriorityQueue;
    dis[s]=0;
    cost[s]=0;
    myPriorityQueue.push(Point(s,dis[s]));
    while(!myPriorityQueue.empty()){
        int u=myPriorityQueue.top().number;//离源点最近的点
        myPriorityQueue.pop();
        for(int i=0;i<graph[u].size();i++){
            int v=graph[u][i].to;
            int l=graph[u][i].length;
            int p=graph[u][i].price;
            if((dis[v]==dis[u]+l && cost[v]>cost[u]+p)|| dis[v]>dis[u]+l){//松弛操作
                dis[v]=dis[u]+l;
                cost[v]=cost[u]+p;
                myPriorityQueue.push(Point(v,dis[v]));
            }
        }
    }
    return;
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0 && m==0){
            break;
        }
        memset(graph,0,sizeof(graph));//图初始化
        fill(dis,dis+n+1,INF);//距离初始化为无穷
        fill(cost,cost+n+1,INF);//花费初始化为无穷
          while(m--){
        int from,to,length,price;
        scanf("%d%d%d%d",&from,&to,&length,&price);
        graph[from].push_back(Edge(to,length,price));
        graph[to].push_back(Edge(from,length,price));
    }
    int s,t;//起点与终点
    scanf("%d%d",&s,&t);
    Dijkstra(s);
    printf("%d %d\n",dis[t],cost[t]);
  }
    return 0;
}

最短路径|上海交大考研复试

描述
N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的最短距离
输入描述:
第一行两个正整数N(2<=N<=100)M(M<=500),表示有N个城市,M条道路 接下来M行两个整数,表示相连的两个城市的编号
输出描述:
N-1行,表示0号城市到其他城市的最短路,如果无法到达,输出-1,数值太大的以MOD 100000 的结果输出。
示例1
输入:
4 4
1 2
2 3
1 3
0 1
复制
输出:
8
9
11

#include <bits/stdc++.h>
using namespace std;
int n, m;//n城市个数、m道路数

const int MAXV = 105;
//大数结构体
struct bign{
    int d[150], len;
    bign(){
        memset(d, 0, sizeof(d));
        len = 0;
    }
};
//输出大数
void print(bign a){
    int len = min(a.len, 5) - 1;//MOD 100000
    while(len > 0 && a.d[len] == 0) len--;//去除余数前导0
    for(int i = len; i >= 0; i--){
        printf("%d", a.d[i]);
    }
}
//高精度a乘以低精度b
bign mul(bign &a, int b){
    bign c;
    int carry = 0;//进位 
    for(int i = 0; i < a.len; i++){
        int tmp = a.d[i] * b + carry;
        c.d[c.len++] = tmp % 10;//个位作为该位结果 
        carry = tmp / 10;//高位部分作为新的进位 
    }
    while(carry != 0){//和加法不同,乘法的进位可能不止一位,因此用while 
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}
//比较大数大小
int cmp(bign a, bign b){
    if(a.len != b.len) return a.len > b.len ? 1 : -1;
    for(int i = a.len - 1; i >= 0; i--){
        if(a.d[i] != b.d[i]) return a.d[i] > b.d[i] ? 1 : -1;
    }
    return 0;
}
//大数加法
bign add(bign &a, bign b){
    int carry = 0;
    bign c;
    for(int i = 0; i < a.len || i < b.len; i++){
        int tmp = a.d[i] + b.d[i] + carry;
        c.d[c.len++] = tmp % 10;
        carry = tmp / 10;
    }
    if(carry) c.d[c.len++] = carry;
    return c;
}
//定义城市结构体
struct City{
    bign dis;
};
bign INF; 
City c[MAXV][MAXV];

void init(){
    INF.len = 500;
    fill(INF.d, INF.d + 500, 9);
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            if(i != j)
                c[i][j].dis = INF;//INF代表不可达
            else {c[i][j].dis.len = 1; c[i][j].dis.d[0] = 0; }
        }
    }
}

void Floyd(){
    for(int k = 0; k < n; k++){
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(cmp(c[i][k].dis, INF) == 0 || cmp(c[k][j].dis, INF) == 0) continue;
                if(cmp(c[i][j].dis, INF) == 0 || cmp(add(c[i][k].dis, c[k][j].dis), c[i][j].dis) == -1){
                    c[i][j].dis = add(c[i][k].dis, c[k][j].dis);
                }
            }
        }
    }
}

int main(){
    scanf("%d %d", &n, &m);
    init();
    bign k;
    k.d[0] = k.len = 1;
    for(int i = 0; i < m; i++){
        int c1, c2;
        scanf("%d %d", &c1, &c2);
        if(cmp(c[c1][c2].dis, INF) != 0){ k = mul(k, 2); continue; }
        c[c1][c2].dis = c[c2][c1].dis = k;   
        k = mul(k, 2);
    }   
    Floyd();//弗洛伊德算法入口
    //输出0号城市到其他城市的最短路
    for(int i = 1; i < n; i++){
        if(cmp(c[0][i].dis, INF) == 0) printf("-1"); //如果无法到达,输出-1
        else print(c[0][i].dis);
        printf("\n"); 
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值