问题描述
给你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<vector>
#include<climits>
#include<queue>
#include<cstring>
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 digkstra(int s){
priority_queue<point>myqueue;//优先队列
dis[s]=0;
cost[s]=0;
myqueue.push(point(s,dis[s]));//最开始加进去的点就是远点自己
while(!myqueue.empty()){
int u =myqueue.top().number;
myqueue.pop();
for(int i=0;i<graph[u].size();i++){ //从u这个点开始的边有几个
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;
myqueue.push(point(v,dis[v]));
}
}
}
return ;
}
int main(){
int n,m; // n是点的个数,m是边的个数
while(cin>>n>>m){
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;
cin>>from>>to>>length>>price;
graph[from].push_back(edge(to,length,price)); //用邻接表表示无向图,所以得记录两次,一去一回
graph[to].push_back(edge(from,length,price));
}
int s,t;
cin>>s>>t;
digkstra(s);
cout<<dis[t]<<' '<<cost[t]<<endl;
}
return 0;
}
知识要点
- memset和fill的用法,头文件是cstring
- point和edge的结构体的定义
- 图的定义是数组,元素为边的vector
- INT_MAX的头文件为climits
- 定义的优先队列,要记得在定义队列元素的时候重载操作符,规定优先级