HN0I2000最优乘车 (最短路变形)
【试题】为了简化城市公共汽车收费系统,某城市决定对大部分的公共汽车都采用一票制,但由于某些公共汽车所经过的停车站太多和路途太长,就采用两票或多票制。经过这种票制改革后,人们坐公共汽车从一个站到另一个站时,就不得不选择一个好的乘车方案,以使他们的乘车费用最低。
为了方便于求出最佳的乘车方案,我们假设:
l 采用一票制的公共汽车,无论从哪个站上车到那个站下车,乘该公共汽车的费用为1(费用单位)。
l 采用多票制的公共汽车,将设立某些站为关键站;那么,如果某人乘该路公共汽车从A站到B站时,不经过任何关键站的乘车费用为1,而经过K个关键站的乘车费用为K+1;所谓经过关键站是指:乘该路公共汽车时,该关键站是其途中的一个站,但它不是上车站也不是下车站;例如,某路公共汽车经过1,2,3,4,*5,6,7,8,9;其中5是关键站,那么,从5站上车到9站下车或从2站上车到5站下车的费用为1,而从4站上车到6站下车的费用将是2。
l 所有公共汽车都是双向行驶的,也即如果公共汽车经过的站点有A和B,那么,你可以乘该公共汽车从A到B或从B到A。
你的任务就是:对于输入文件中给出的公共汽车各停车站,和某乘客的起点站A和终点站B,请你编程为乘客求出最佳的乘车方案,使得他的乘车费用最少。
输入:第1行为N、R、A和B,其中N为城市公共汽车停车站的总个数,这些停车站被统一编号为1、2、……、N;R为公共汽车总路数。A为起点站的编号,B为终点站的编号。(1≤N≤1000,1≤R≤300,每路公共汽车的最多站点数为20)。数据之间用空格分开。
第2行到R+1行的每一行为一路公共汽车经过的停车站编号,停车站编号的排列顺序是该路公共汽车按一个方向行车顺序依次经过的停车站,如为关键停车站,则其编号的前面有一个*。每行数据之间用空格分开。
输出:从A站到B站所需的最少费用。如果不能乘这些公共汽车从A到B,输出-1。
输入输出示例:
INPUT4.TXT
12 4 1 12
1 2 3 *4 5 6 7
1 2 3 8
8 4 5 9
7 6 5 *9 10 11 12
OUTPUT4.TXT
3
解题报告
好稀有的题目,在网上根本找不到的说。
很典型的最短路。对于每一条公交线路,我们让其中的每一个站点互相建边,使其权值为票价,注意边界问题,起点与终点为关键站不计入票价中。
用堆优dijkstra即可。
#include<bits/stdc++.h> #define Pair pair<int,int> #define MAXN 1000+10 #define MAXM 600000+1 using namespace std; int n,m,num,head[MAXN],s,t,dis[MAXN],v[MAXM]; int pre[MAXN]; int read(int &k) { int in=0,j=0;char c; c=getchar(); for(;c>‘9‘||c<‘0‘;c=getchar()) { if(c==‘\n‘) return 0; if(c==‘*‘) j=1; } for(;c<=‘9‘&&c>=‘0‘;c=getchar()) in=in*10+c-‘0‘; k=in; if(j) return 2; return 1; } struct Edge{ int dis,next,to,exi,from; }edge[MAXM]; void add(int from,int to,int dis) { edge[++num].next=head[from]; edge[num].to=to; edge[num].dis=dis; edge[num].from=from; head[from]=num; edge[num].exi=1; } void dij() { memset(dis,0,sizeof(dis)); memset(v,0,sizeof(v)); priority_queue<Pair,vector<Pair>,greater<Pair> > h; for(int i=1;i<=n;i++) dis[i]=2147483647; dis[s]=0; h.push(Pair(dis[s],s)); while(h.size()>0) { int k=h.top().second;h.pop(); if(v[k]) continue; v[k]=1; for(int i=head[k];i;i=edge[i].next) if(dis[k]+edge[i].dis<dis[edge[i].to]&&edge[i].exi==1) { dis[edge[i].to]=dis[k]+edge[i].dis; h.push(Pair(dis[edge[i].to],edge[i].to)); pre[edge[i].to]=edge[i].from; } } } int main() { freopen("bus.in","r",stdin); freopen("bus.out","w",stdout); scanf("%d%d%d%d\n",&n,&m,&s,&t); for(int i=1;i<=m;i++) { int x,o,np=0;int p[MAXN][3],k=1; while(1) { o=read(x);if(o==0) break; else if(o==2) p[++np][0]=x,p[np][1]=k,k++,p[np][2]=k; else p[++np][0]=x,p[np][1]=p[np][2]=k; } for(int i=1;i<=np;i++) { for(int j=1+i;j<=np;j++) { int money=min( min(abs(p[i][1]-p[j][1]),abs(p[i][2]-p[j][2])) ,min(abs(p[i][1]-p[j][2]),abs(p[i][2]-p[j][1]))); add(p[i][0],p[j][0],money+1); add(p[j][0],p[i][0],money+1); } } } dij(); if(dis[t]>=2147483647) printf("-1\n"); else printf("%d\n",dis[t]); return 0; }