版权声明:本篇随笔版权归作者Etta(http://www.cnblogs.com/Etta/)所有,转载请保留原地址!
为了简化城市公共汽车收费系统,某城市决定对大部分的公共汽车都采用一票制,但由于某些公共汽车所经过的停车站太多和路途太长,就采用两票或多票制。经过这种票制改革后,人们坐公共汽车从一个站到另一个站时,就不得不选择一个好的乘车方案,以使他们的乘车费用最低。
为了方便于求出最佳的乘车方案,我们假设:
采用一票制的公共汽车,无论从哪个站上车到那个站下车,乘该公共汽车的费用为1(费用单位)。
采用多票制的公共汽车,将设立某些站为关键站;那么,如果某人乘该路公共汽车从A站到B站时,不经过任何关键站的乘车费用为1,而经过K个关键站的乘车费用为K+1;所谓经过关键站是指:乘该路公共汽车时,该关键站是其途中的一个站,但它不是上车站也不是下车站;例如,某路公共汽车经过1,2,3,4,*5,6,7,8,9;其中5是关键站,那么,从5站上车到9站下车或从2站上车到5站下车的费用为1,而从4站上车到6站下车的费用将是2。
所有公共汽车都是双向行驶的,也即如果公共汽车经过的站点有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
一、分析问题
这道最短路的题亮点在于建边以及字符串的输入与处理。第一种实现方法较为繁琐,需要自行考虑到多种建边限制,很容易就漏掉特殊情况。而第二种实现方法归纳出一个通式,使得程序简洁而清晰起来。
二、解决问题
每一条线路上车站间根据*两两建边+SPFA
Tips:
1.输入字符串时用getline(cin,s1);
2.其实可以用邻接链表
三、代码实现
方法1:
1 #include<cstring> 2 #include<iostream> 3 #include<string> 4 #include<queue> 5 #include<cstdio> 6 using namespace std; 7 8 const int A=1010,B=310,inf=4e8; 9 int n,m,a,b; 10 int g[A][A],u[A][A],s[A],c[25],dis[A],ex[A]; 11 string ch; 12 queue<int>q; 13 14 void init() 15 { 16 scanf("%d%d%d%d ",&n,&m,&a,&b); 17 18 for(int i=1;i<=n-1;++i) 19 for(int j=i+1;j<=n;++j) 20 g[i][j]=g[j][i]=inf; 21 22 for(int i=1;i<=m;++i) 23 { 24 getline(cin,ch); 25 int ss=1,l=ch.size(); 26 int d[25],r=0; 27 memset(d,0,sizeof(d)); 28 memset(c,0,sizeof(c)); 29 for(int k=0;k<l;) 30 { 31 while(ch[k]==' '&&k<=l-1)++k; 32 if(k==l)break; 33 if(ch[k]=='*')d[++r]=ss,++k; 34 while(ch[k]>='0'&&ch[k]<='9') 35 c[ss]=c[ss]*10+ch[k]-'0',++k; 36 ++ss; 37 } 38 ss-=1; 39 if(!r) 40 { 41 for(int j=1;j<=ss-1;++j) 42 for(int k=j+1;k<=ss;++k) 43 { 44 if(g[c[j]][c[k]]==inf) 45 { 46 u[c[j]][++s[c[j]]]=c[k]; 47 u[c[k]][++s[c[k]]]=c[j]; 48 } 49 g[c[j]][c[k]]=min(g[c[j]][c[k]],1); 50 g[c[k]][c[j]]=g[c[j]][c[k]]; 51 } 52 } 53 else 54 { 55 int out=1,in=1,uu=0,vv; 56 bool o1=0,o2=0; 57 for(int j=1;j<=ss-1;++j) 58 { 59 if(j==d[out]&&out<=r)uu=out++,o1=1; 60 if(j>d[out]&&out<=r)uu=out++; 61 in=1;vv=0; 62 for(int k=j+1;k<=ss;++k) 63 { 64 if(k==d[in]&&in<=r)vv=in++,o2=1; 65 while(k>d[in]&&in<=r)vv=in++; 66 if(g[c[j]][c[k]]==inf) 67 { 68 u[c[j]][++s[c[j]]]=c[k]; 69 u[c[k]][++s[c[k]]]=c[j]; 70 } 71 if((o1&&o2)||(!o1&&o2))g[c[j]][c[k]]=min(g[c[j]][c[k]],vv-uu),o2=0; 72 else g[c[j]][c[k]]=min(g[c[j]][c[k]],vv-uu+1); 73 g[c[k]][c[j]]=g[c[j]][c[k]]; 74 } 75 o1=0; 76 } 77 } 78 } 79 } 80 81 void SPFA() 82 { 83 for(int i=1;i<=n;++i)dis[i]=inf; 84 dis[a]=0; 85 q.push(a); 86 while(!q.empty()) 87 { 88 int t=q.front(); 89 q.pop(); 90 ex[t]=0; 91 for(int i=1;i<=s[t];++i) 92 { 93 int y=u[t][i]; 94 if(dis[t]+g[t][y]<dis[y]) 95 { 96 dis[y]=dis[t]+g[t][y]; 97 if(!ex[y]) 98 { 99 ex[y]=1; 100 q.push(y); 101 } 102 } 103 } 104 } 105 if(dis[b]==inf)printf("-1"); 106 else printf("%d ",dis[b]); 107 } 108 109 int main() 110 { 111 init(); 112 SPFA(); 113 return 0; 114 }
方法2:
1 #include<cstring> 2 #include<iostream> 3 #include<queue> 4 #include<cstdio> 5 using namespace std; 6 7 const int A=1010,B=310,inf=4e8; 8 int n,m,a,b; 9 int g[A][A],u[A][A],s[A],c[25],dis[A],ex[A]; 10 int e[A][A],f[A][A],y[A][A]; 11 string ch; 12 queue<int>q; 13 void init(); 14 void SPFA(); 15 16 int main() 17 { 18 init(); 19 SPFA(); 20 return 0; 21 } 22 23 void init() 24 { 25 scanf("%d%d%d%d ",&n,&m,&a,&b); 26 27 for(int i=1;i<=n-1;++i) 28 for(int j=i+1;j<=n;++j) 29 g[i][j]=g[j][i]=inf; 30 31 for(int i=1;i<=m;++i) 32 { 33 getline(cin,ch); 34 int ss=1,l=ch.size(); 35 int d[25],r=0; 36 for(int k=0;k<l;) 37 { 38 while(ch[k]==' '&&k<=l-1)++k; 39 if(k==l)break; 40 if(ch[k]=='*')f[i][ss]=1,++k; 41 while(ch[k]>='0'&&ch[k]<='9') 42 e[i][ss]=e[i][ss]*10+ch[k]-'0',++k; 43 ++ss; 44 } 45 e[i][0]=ss; 46 } 47 48 for(int i=1;i<=m;++i) 49 { 50 for(int j=1;j<=e[i][0];++j) 51 { 52 y[i][j]+=y[i][j-1]; 53 if(f[i][j])++y[i][j]; 54 } 55 } 56 57 for(int i=1;i<=m;++i) 58 { 59 for(int j=1;j<=e[i][0]-1;++j) 60 { 61 for(int k=j+1;k<=e[i][0];++k) 62 { 63 int x=e[i][j],z=e[i][k]; 64 if(g[x][z]==inf) 65 { 66 u[x][++s[x]]=z; 67 u[z][++s[z]]=x; 68 } 69 g[x][z]=min(g[x][z],y[i][k-1]-y[i][j]+1); 70 g[z][x]=g[x][z]; 71 } 72 } 73 } 74 } 75 76 void SPFA() 77 { 78 for(int i=1;i<=n;++i)dis[i]=inf; 79 dis[a]=0; 80 q.push(a); 81 while(!q.empty()) 82 { 83 int t=q.front(); 84 q.pop(); 85 ex[t]=0; 86 for(int i=1;i<=s[t];++i) 87 { 88 int y=u[t][i]; 89 if(dis[t]+g[t][y]<dis[y]) 90 { 91 dis[y]=dis[t]+g[t][y]; 92 if(!ex[y]) 93 { 94 ex[y]=1; 95 q.push(y); 96 } 97 } 98 } 99 } 100 if(dis[b]==inf)printf("-1"); 101 else printf("%d ",dis[b]); 102 }