• 蓝桥杯地铁换乘问题


    为解决交通难题,某城市修建了若干条交错的地铁线路,线路名及其所属站名如stations.txt所示。

    线1

    苹果园

    ....

    四惠东

    线2

    西直门

    车公庄

    ....

    建国门

    线4

    ....

    其中第一行数据为地铁线名,接下来是该线的站名。

    当遇到空行时,本线路站名结束。

    下一行开始又是一条新线....直到数据结束。

    如果多条线拥有同一个站名,表明:这些线间可以在该站换车。

    为引导旅客合理利用线路资源,解决交通瓶颈问题,该城市制定了票价策略:

    1. 每条线路可以单独购票,票价不等。

    2. 允许购买某些两条可换乘的线路的联票。联票价格低于分别购票。

    单线票价和联合票价如 price.txt 所示。

    线1 180

    .....

    线13 114

    线1,线2 350

    线1,线10 390

    .....

    每行数据表示一种票价

    线名与票价间用空格分开。如果是联票,线名间用逗号分开。

    联票只能包含两条可换乘的线路。

    现在的问题是:根据这些已知的数据,计算从A站到B站最小花费和可行的换乘方案。

    比如,对于本题目给出的示例数据

    如果用户输入:

    五棵松,奥体中心

    程序应该输出:

    -(线1,线10)-线8 = 565

    如果用户输入:

    五棵松,霍营

    程序应该输出:

    -线1-(线4,线13) = 440

    可以看出,用户输入的数据是:起始站,终到站,用逗号分开。

    程序输出了购票方案,在括号中的表示联票,短横线(-)用来分开乘车次序。

    等号后输出的是该方案的花费数值。

    分析:

    自顶向下求解。先根据需求定义求解流程(顺序),再根据每个流程定义数据结构,函数(包括功能,参数),最后实现每个函数。对于线路信息的数据结构定义,因为每个线路的站名均为汉字,且有不少重复站名,并且汉字间比较更费时间,所以无论从空间还是时间考虑都应将其映射到其它数据结构,这是将站名与整数建立映射关系,每个站名都与一个整数对应,可以使用C++map完成此功能或自已用HASH表实现,这里使用效率低些但实现简单的字符串指针数组实现,价格的数据结构实现与此类似。对于结果的计算有很多情况需要处理,如:

    1. 当某个线路可直达时,是否还查找该线路可转乘到达的线路(以下程序查找);

    2. 当同一联票线路有多种转乘方案时,该联票线路输出几回(以下程序有几种方案就输出几回);

    3. 当有转乘线路可到达但无联票价格时是否不输出该方案(以下程序不输出)。

    WIN32控制台程序不能输入中文汉字解决办法:

    打开注册表(开始--运行--输入"regedit"回车),将"HKEY_CURRENT_USER--Console"中的"LoadConIme"修改为"1",然后在控制台中按"Ctrl+Space(空格)"可切换中文或英文输入。

    解:

    1. #include <stdio.h>  
    2. #include <string.h>  
    3. #include <stdlib.h>  
    4. #include <io.h>  
    5. #include <ctype.h>  
    6.   
    7. #define FALSE   false  
    8. #define TRUE    true  
    9. #define BOOL    bool  
    10.   
    11. typedef void    VOID;  
    12. typedef int     INT32;  
    13. typedef char    INT8;  
    14. typedef long    LONG;  
    15.   
    16. #define MAX_LINES           50  
    17. #define LINE_STATIONS_NUM   100  
    18. #define ALL_STATIONS_NUM    (MAX_LINES*LINE_STATIONS_NUM)  
    19. #define FILE_BUF_NUM        100  
    20. #define INPUT_BUF_NUM       50  
    21. #define OUPUT_BUF_NUM       100  
    22. #define MAX_RES_NUM         20  
    23. #define MAX_TWO_PRICE_NUM   100  
    24. //线  
    25. #define FLAG1               -49  
    26. #define FLAG2               -33  
    27.   
    28. typedef struct LINE_ST  
    29. {  
    30.     INT32 ln;       //线号  
    31.     INT32 num;      //线内站数目  
    32.     INT32 price;    //线钱  
    33.     INT32 ns[LINE_STATIONS_NUM];    //线内站号  
    34. }Line;  
    35.   
    36. typedef struct TWO_PRICE_ST  
    37. {  
    38.     INT32 num1;     //线路号  
    39.     INT32 num2;     //线路号  
    40.     INT32 price;    //联票价格  
    41. }TwoPrice;          //联票价格  
    42.   
    43. /***************************************************************************** 
    44. * 函数:ReadLines                                                           * 
    45. * 参数:stLine:线路信息结构体.                                                 * 
    46. *      pStaTable:站名(字符串)-序号(stLine.ns,stLine.cro)表.                  * 
    47. *      szLinesFile:线路文件名.                                                * 
    48. * 返回值:返回TRUE表示读取成功,FALSE失败.                                  * 
    49. * 功能:读取线路信息.                                                         * 
    50. *****************************************************************************/  
    51. BOOL ReadLines(Line *stLine, INT8 *pStaTable[], INT8 *szLinesFile)  
    52. {  
    53.     FILE *fp;  
    54.     INT32 i,j;  
    55.     INT32 n, ln;            //站对应的数字,线号,  
    56.     INT8 str[FILE_BUF_NUM]; //文件缓冲  
    57.   
    58.     n = 0;  
    59.     ln = -1;  
    60.   
    61.     for(i=0; i<ALL_STATIONS_NUM; i++)  
    62.         pStaTable[i] = NULL;  
    63.   
    64.     for(i=0; i<MAX_LINES; i++)  
    65.     {  
    66.         stLine[i].ln = -1;  
    67.         stLine[i].price = 0;  
    68.         stLine[i].num = 0;  
    69.         for(j=0; j<LINE_STATIONS_NUM; j++)  
    70.         {  
    71.             stLine[i].ns[j] = 0;  
    72.         }  
    73.     }  
    74.       
    75.   
    76.     if(NULL == (fp = fopen(szLinesFile, "r")))  
    77.     {  
    78.         printf("Err: Open stations.txt!\n");  
    79.         return FALSE;  
    80.     }  
    81.   
    82.     while(fgets(str, FILE_BUF_NUM, fp))  
    83.     {     
    84.         if('\n' == str[0])//空行?  
    85.             continue;  
    86.   
    87.         // 去掉尾部不必要的换行符号  
    88.         if(str[strlen(str)-1] == '\n' )  
    89.             str[strlen(str)-1] = '\0';  
    90.   
    91.         if(FLAG1==str[0] && FLAG2==str[1])  //新线号?  
    92.         {  
    93.             ln++;  
    94.             stLine[ln].ln = atoi(&str[2]);  
    95.             continue;  
    96.         }  
    97.           
    98.         for(i=0; i<n; i++)  
    99.         {  
    100.             if(0 == strcmp(str, pStaTable[i]))  
    101.                 break;  
    102.         }  
    103.   
    104.         if(i==n)  
    105.         {  
    106.             pStaTable[i] = (INT8 *)malloc(sizeof(INT8)*LINE_STATIONS_NUM);  
    107.             strcpy(pStaTable[i], str);  
    108.             n++;  
    109.         }  
    110.   
    111.         stLine[ln].ns[stLine[ln].num] = i;  
    112.         stLine[ln].num++;  
    113.   
    114.     }  
    115.   
    116.     fclose(fp);  
    117.   
    118. /* 
    119.     for(i=0; NULL!=pStaTable[i]; i++) 
    120.     { 
    121.         printf("%d:%s\n", i, pStaTable[i]); 
    122.     } 
    123.  
    124.     for(i=0; -1!=stLine[i].ln; i++) 
    125.     { 
    126.         printf("线%d: %d\n", stLine[i].ln, stLine[i].num); 
    127.         for(j=0; j<stLine[i].num; j++) 
    128.         { 
    129.             printf("%d:%s\n", stLine[i].ns[j], pStaTable[stLine[i].ns[j]]); 
    130.         } 
    131.     } 
    132. */  
    133.   
    134.     return TRUE;  
    135. }  
    136.   
    137. /***************************************************************************** 
    138. * 函数:FreeReadLines                                                       * 
    139. * 参数:pStaTable:站名(字符串)-序号(stLine.ns,stLine.cro)表.                    * 
    140. * 返回值:无.                                                                 * 
    141. * 功能:释放动态分配的pStaTable空间.                                             * 
    142. *****************************************************************************/  
    143. VOID FreeReadLines(INT8 *pStaTable[])  
    144. {  
    145.     INT32 i;  
    146.   
    147.     for(i=0; i<ALL_STATIONS_NUM; i++)  
    148.     {  
    149.         if(NULL != pStaTable[i])  
    150.             free(pStaTable[i]);  
    151.     }  
    152. }  
    153.   
    154. /***************************************************************************** 
    155. * 函数:GetInput                                                            * 
    156. * 参数:szStart:起点站名.                                                   * 
    157. *      szDes:终点站名.                                                       * 
    158. * 返回值:无.                                                                 * 
    159. * 功能:读取用户输入的起点,终点.                                           * 
    160. *****************************************************************************/  
    161. VOID GetInput(INT8 *szStart, INT8 *szDes)   //获取用户输入  
    162. {  
    163.     INT8 buf[INPUT_BUF_NUM];  
    164.     INT32 i,j;  
    165.     printf("请输入起始站和终点站(英文逗号隔开)......\n");  
    166.     //英文逗号不能作为字符串分割符,即scanf("%s,%s", szStart, szDes)是错误的  
    167.     fflush(stdin);  
    168.     gets(buf);;  
    169.     for(i=0; ','!=buf[i]; i++)  
    170.         szStart[i] = buf[i];  
    171.     szStart[i++] = '\0';  
    172.     for(j=0; '\0'!=buf[i]; i++,j++)  
    173.         szDes[j] = buf[i];  
    174.     szDes[j] = '\0';  
    175.   
    176. //  printf("%s,%s\n", szStart, szDes);  
    177. }  
    178.   
    179. /***************************************************************************** 
    180. * 函数:ReadLines                                                           * 
    181. * 参数:stLine:线路信息结构体.                                                 * 
    182. *      pStaTable:站名(字符串)-序号(stLine.ns,stLine.cro)表.                  * 
    183. *      szStart:起点站名.                                                     * 
    184. *      szDes:终点站名.                                                       * 
    185. *      aRes:结果,aRes[i][0]为线路1在stLine中序号,aRes[i][1]为线路2(若有) * 
    186. *           在stLine中序号.                                                  *     
    187. * 返回值:返回TRUE表示计算路线成功,FALSE失败.                                * 
    188. * 功能:计算起点到终点的可行乘车方案.                                         * 
    189. *****************************************************************************/  
    190. BOOL CalcLines(Line *stLine, INT8 *pStaTable[], INT8 *szStart, INT8 *szDes,   
    191.                INT32 aRes[][2]) //计算结果  
    192. {  
    193.     INT32 i,j,k,l,m,n;  
    194.     INT32 nStart = -1, nDes = -1;   //起点,终点-序号(stLine.ns,stLine.cro)表  
    195.     BOOL  bStartFlag = FALSE, bDesFlag = FALSE; //找到起点,终点标志  
    196.     INT32 nNotFind;                     //未找到的(起点或终点)  
    197.     INT32 nResCount = 0;                //结果计数  
    198.     INT32 nLoop;                        //循环次数  
    199.   
    200.     aRes[0][0] = -1;  
    201.     aRes[0][1] = -1;  
    202.   
    203.     //查找起点,终点在stLine中序号  
    204.     for(i=0; NULL!=pStaTable[i]; i++)  
    205.     {  
    206.         if(0 == strcmp(szStart, pStaTable[i]))  
    207.             nStart = i;  
    208.         if(0 == strcmp(szDes, pStaTable[i]))  
    209.             nDes = i;  
    210.     }  
    211.     if(-1==nStart || -1==nDes)  
    212.         return FALSE;  
    213.   
    214.     //查找保存结果  
    215.     for(i=0; -1!=stLine[i].ln; i++)  
    216.     {  
    217.         bStartFlag = FALSE;  
    218.         bDesFlag = FALSE;  
    219.         for(k=0; k<stLine[i].num; k++)  
    220.         {  
    221.             if(nStart == stLine[i].ns[k])  
    222.                 bStartFlag = TRUE;  
    223.             if(nDes == stLine[i].ns[k])  
    224.                 bDesFlag = TRUE;  
    225.         }  
    226.   
    227.         if(!bStartFlag && !bDesFlag)    //未找到起点和终点?  
    228.             continue;  
    229.   
    230.         nLoop = 1;  
    231.         if(bStartFlag && bDesFlag)  //找到起点和终点?  
    232.         {  
    233.             aRes[nResCount][0] = i;  
    234.             aRes[nResCount][1] = -1;//?  
    235.             nResCount++;  
    236.             aRes[nResCount][0] = -1;  
    237.             aRes[nResCount][1] = -1;  
    238.             nLoop = 2;      //以此线为起点或终点寻找可换乘路线,虽然一般没人这么做...  
    239.         }  
    240.           
    241.         for(l=0; l<nLoop; l++)  
    242.         {  
    243.             if(1 == l)  
    244.                 bStartFlag = !bStartFlag;  
    245.   
    246.             if(bStartFlag)  //只找到起点?  
    247.                 nNotFind = nDes;  
    248.             else//只找到终点  
    249.                 nNotFind = nStart;  
    250.   
    251.             //找是否存在转乘线路可到达  
    252.             for(j=i+1; -1!=stLine[j].ln; j++)  
    253.             {  
    254.                 for(k=0; k<stLine[j].num; k++)  
    255.                 {  
    256.                     if(nNotFind == stLine[j].ns[k])  
    257.                         break;  
    258.                 }  
    259.                 if(k != stLine[j].num)  //找到另一点  
    260.                 {  
    261.                     for(m=0; m<stLine[i].num; m++)  
    262.                         for(n=0; n<stLine[j].num; n++)  
    263.                         {  
    264.                             if(stLine[i].ns[m] == stLine[j].ns[n]  
    265.                                 && nStart!=stLine[i].ns[m] && nDes!=stLine[i].ns[m]  
    266.                                 && nStart!=stLine[j].ns[n] && nDes!=stLine[j].ns[n])    //转乘可到达?  
    267.                             {  
    268.                                 aRes[nResCount][0] = i;  
    269.                                 aRes[nResCount][1] = j;  
    270.                                 nResCount++;  
    271.                                 aRes[nResCount][0] = -1;  
    272.                                 aRes[nResCount][1] = -1;  
    273.                             }  
    274.                         }  
    275.                 }  
    276.                 else  
    277.                 {  
    278.                     continue;  
    279.                 }  
    280.             }  
    281.         }  
    282.           
    283.     }  
    284.   
    285. //  for(i=0; -1!=aRes[i][0]; i++)  
    286. //      printf("Line1:%d, Line2:%d\n", aRes[i][0], aRes[i][1]);  
    287.   
    288.     return TRUE;  
    289. }  
    290.   
    291. /***************************************************************************** 
    292. * 函数:ReadLinesPrice                                                          * 
    293. * 参数:stLine:线路信息结构体.                                                 * 
    294. *      sttwoPrice:联票价格.                                                  * 
    295. *      szPriceFile:票价文件名.                                                *    
    296. * 返回值:返回TRUE表示读取文件成功,FALSE失败.                                * 
    297. * 功能:读取票价.                                                           * 
    298. *****************************************************************************/  
    299. BOOL ReadLinesPrice(Line *stLine, TwoPrice *sttwoPrice,  
    300.                     INT8 *szPriceFile)//获取线路价格  
    301. {  
    302.     FILE *fp;  
    303.     INT8 c;  
    304.     INT32 line1, line2;  
    305.     INT32 price;  
    306.     INT32 i, n = 0;  
    307.   
    308.     sttwoPrice[0].num1 = -1;    //结束标志  
    309.   
    310.     if(NULL == (fp=fopen(szPriceFile, "r")))  
    311.     {  
    312.         printf("Err: Do not open %s\n", szPriceFile);  
    313.         return FALSE;  
    314.     }  
    315.   
    316.     while((FLAG1 == (c=fgetc(fp))) && EOF!=c)  
    317.     {  
    318. //      fPos = ftell(fp);  
    319.         if((FLAG2 != (c=fgetc(fp))))  
    320.         {  
    321. //          if(0 != fseek(fp, fPos, SEEK_SET))  //文件指针向前移动1字节(返回判断该值是否等于FLAG1)  
    322. //          {  
    323. //              printf("Err: seek file err...\n");  
    324. //              return FALSE;  
    325. //          }  
    326.             if(EOF != c)    //文件指针向前移动1字节(返回判断该值是否等于FLAG1)  
    327.                 ungetc(c, fp);  
    328.             else  
    329.             {  
    330.                 fclose(fp);  
    331.                 return TRUE;  
    332.             }  
    333.             continue;  
    334.         }  
    335.   
    336.         ////找到“线”字,读完这一行在返回  
    337.   
    338.         //读线号  
    339.         line1 = 0;  
    340.         while((' ' != (c=fgetc(fp))) && ','!=c)   
    341.         {  
    342.             line1 = line1 * 10 + c - '0';   
    343.         }  
    344.   
    345.         price = 0;  
    346.         if(' ' == c)    //此行为单线价格?  
    347.         {  
    348.             while('\n' != (c=getc(fp)))  
    349.                 price = price * 10 + c - '0';  
    350.   
    351.             //记录单线价格  
    352.             for(i=0; i<MAX_LINES; i++)     
    353.             {  
    354.                 if(line1 == stLine[i].ln)  
    355.                 {  
    356.                     stLine[i].price = price;  
    357.                     break;  
    358.                 }  
    359.             }  
    360.         }  
    361.         else    //联票价格行  
    362.         {  
    363.             while(FLAG1 != (c=getc(fp)));  
    364.             c = getc(fp);   //FLAG2  
    365.   
    366.             //读第二个线号  
    367.             line2 = 0;  
    368.             while(' ' != (c=getc(fp)))  
    369.                 line2 = line2*10 + c - '0';   
    370.   
    371.             while('\n' != (c=getc(fp)) && EOF != c)  
    372.             {  
    373.                 if(isdigit(c))  
    374.                     price = price * 10 + c- '0';  
    375.             }  
    376.   
    377.             //记录联票价格  
    378.             sttwoPrice[n].num1 = line1;  
    379.             sttwoPrice[n].num2 = line2;  
    380.             sttwoPrice[n].price = price;  
    381.             n++;  
    382.             sttwoPrice[n].num1 = -1;  
    383.         }  
    384.   
    385.     }  
    386.   
    387.     fclose(fp);  
    388.   
    389. //  for(i=0; -1!=stLine[i].ln; i++)  
    390. //      printf("Line:%d Price:%d\n", stLine[i].ln, stLine[i].price);  
    391. //  for(i=0; -1!=sttwoPrice[i].num1; i++)  
    392. //      printf("Line1:%d Line2:%d Price:%d\n", sttwoPrice[i].num1,   
    393. //              sttwoPrice[i].num2, sttwoPrice[i].price);  
    394.   
    395.     return TRUE;  
    396. }  
    397.   
    398. /***************************************************************************** 
    399. * 函数:OutputRes                                                           * 
    400. * 参数:aRes:结果.                                                            *    
    401. *      stLine:线路信息结构体.                                               * 
    402. *      sttwoPrice:联票价格.                                                  * 
    403. * 返回值:无.                                                                 * 
    404. * 功能:输出结果.                                                           * 
    405. *****************************************************************************/  
    406. VOID OutputRes(INT32 aRes[][2], Line *stLine, TwoPrice *sttwoPrice) //输出结果  
    407. {  
    408.     INT32 i, j;  
    409.     INT32 aPrice[MAX_RES_NUM];  
    410.     INT32 nMinNum = -1; //最小价格序号(aRes中)  
    411.     INT32 nMinPrice  = ~(1<<(sizeof(INT32)*8 - 1))  ;         //最小价格  
    412.   
    413.     for(i=0; i<MAX_RES_NUM; i++)  
    414.         aPrice[i] = -1;  
    415.   
    416.     //找出最便宜的结果  
    417.     for(i=0; -1!=aRes[i][0]; i++)  
    418.     {  
    419.         if(-1 == aRes[i][1])    //单线?  
    420.         {  
    421.             aPrice[i] = stLine[aRes[i][0]].price;  
    422.             if(stLine[aRes[i][0]].price < nMinPrice)  
    423.             {  
    424.                 nMinPrice = stLine[aRes[i][0]].price;  
    425.                 nMinNum = i;                  
    426.             }  
    427.         }  
    428.         else    //双线  
    429.         {  
    430.             for(j=0; -1!=sttwoPrice[j].num1; j++)  
    431.             {  
    432.                 if((stLine[aRes[i][0]].ln==sttwoPrice[j].num1 && stLine[aRes[i][1]].ln==sttwoPrice[j].num2)  
    433.                     || (stLine[aRes[i][0]].ln==sttwoPrice[j].num2 && stLine[aRes[i][1]].ln==sttwoPrice[j].num1))  
    434.                 {  
    435.                     aPrice[i] = sttwoPrice[j].price;  
    436.                     if(sttwoPrice[j].price < nMinPrice)  
    437.                     {  
    438.                         nMinPrice = sttwoPrice[j].price;  
    439.                         nMinNum = i;  
    440.                     }  
    441.                 }  
    442.   
    443.             }  
    444.         }  
    445.     }  
    446.   
    447.     //输出  
    448.     for(i=0; -1!=aRes[i][0]; i++)  
    449.     {  
    450.         if(i != nMinNum && -1 != aPrice[i])  
    451.         {  
    452.             if(-1 == aRes[i][1])    //单线  
    453.             {  
    454.                 printf("-线%d", stLine[aRes[i][0]].ln);  
    455.             }  
    456.             else//双线  
    457.             {  
    458.                 printf("-(线%d,线%d)", stLine[aRes[i][0]].ln, stLine[aRes[i][1]].ln);  
    459.             }  
    460.         }  
    461.     }  
    462.     if(-1 != nMinNum)  
    463.     {  
    464.         if(-1==aRes[nMinNum][1])  
    465.             printf("-线%d=%d\n", stLine[aRes[nMinNum][0]].ln, nMinPrice);  
    466.         else  
    467.             printf("-(线%d,线%d)=%d\n", stLine[aRes[nMinNum][0]].ln, stLine[aRes[nMinNum][1]].ln, nMinPrice);  
    468.     }  
    469. }  
    470.   
    471. BOOL f()  
    472. {  
    473.     INT32   aRes[MAX_RES_NUM][2];                           //结果(aRes[i][],i为stLine中序号)  
    474.     INT8    *pStaTable[ALL_STATIONS_NUM];                   //站名(字符串)-序号(stLine.ns,stLine.cro)表  
    475.     INT8    szStart[INPUT_BUF_NUM], szDes[INPUT_BUF_NUM];   //起点,终点  
    476.     INT8    *szLinesFile = "stations.txt";  
    477.     INT8    *szPriceFile = "price.txt";   
    478.     Line    stLine[MAX_LINES];                              //线  
    479.     TwoPrice    stTwoPrice[MAX_TWO_PRICE_NUM];              //2个线路的合票价格  
    480.   
    481.     if(!ReadLines(stLine, pStaTable, szLinesFile))          //获取线路信息  
    482.         return FALSE;  
    483.   
    484.     if(!ReadLinesPrice(stLine, stTwoPrice, szPriceFile))    //获取线路价格  
    485.         return FALSE;  
    486.   
    487.     GetInput(szStart, szDes);                               //获取用户输入  
    488.   
    489.     CalcLines(stLine, pStaTable, szStart, szDes, aRes);     //计算结果  
    490.   
    491.     OutputRes(aRes, stLine, stTwoPrice);                    //输出结果  
    492.   
    493.     FreeReadLines(pStaTable);                               //释放已分配空间  
    494.   
    495.     return TRUE;  
    496. }  
    497.   
    498. INT32 main(INT32 argc, INT32 *argv[])  
    499. {  
    500.   
    501.     f();  
    502.   
    503.     return 0;  
    504. }  
  • 相关阅读:
    nodejs windows下安装运行
    第一篇博客
    vc 动态链接库编程2
    vc 动态链接库编程
    原生js实现图片在线预览
    玩转 css3
    CSS Hack整理
    PHP stdClass Object转array
    aptana studio3 汉化方法
    玩转 css3 续
  • 原文地址:https://www.cnblogs.com/lixingle/p/3312991.html
Copyright © 2020-2023  润新知