畅通工程续
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;
}