最短路径问题――这道题绝对经典(华为2014年校招机试题)

2014-11-23 23:21:20 · 作者: · 浏览: 5
问题描述
高级题:地铁换乘
已知2条地铁线路,其中A为环线,B为东西向线路,线路都是双向的。经过的站点名分别如下,两条线交叉的换乘点用T1、T2表示。编写程序,任意输入两个站点名称,输出乘坐地铁最少需要经过的车站数量(含输入的起点和终点,换乘站点只计算一次)。
地铁线A(环线)经过车站:A1 A2 A3 A4 A5 A6 A7 A8 A9 T1 A10 A11 A12 A13 T2 A14 A15 A16 A17 A18
地铁线A(直线)经过车站:B1 B2 B3 B4 B5 T1 B6 B7 B8 B9 B10 T2 B11 B12 B13 B14 B15
输入:输入两个不同的站名
输出:输出最少经过的站数,含输入的起点和终点,换乘站点只计算一次
思路解析:
我不知道大家看到这道题是怎么思考的,我看到这道题第一反映就是他要我求最短路径,而最短路径几种常用的算法是Dijkstra,Floyd和A*算法,而A*算法尤为常用(我对A*算法比较熟悉,之前做过这个项目),所以我不佳思索的就是开始用A*算法写了。先开始通过名字构建图....因为说实话这个图没有什么规律,必须一点点构建,特别是节点出的连接,构建图我大概花了20分钟,然后开始写A*算法。A*算法一个最关键的问题就是求代价值,而实际上这个问题并不好求代价值,但也不是不能求。我花了30分钟设计出代价值的函数,于是我开始反思,我觉得这样下去,加上我把A*算法重头写一遍,加上 调试应该还要1个小时左右的时间。可是华为这道题给我们的总共时间只有一个小时,于是我开始否认我的这一条思路了。
然后我又很自然的想到了,对于这种题用图的深度遍历,他将会得出多条路径,然后我可以选取最短的一条。这貌似是一个不错的方法,可是这样做的前提是我必须还要构建一个图出来,这样下来构建图依旧要花费20分钟,只有40分感觉时间比较紧张,可能对与容错处理和健壮性仍旧会考虑不佳。我又开始否认我这条思路。
我想,到底有没有一种编码效率更高的方法可以在最短时间内完成这个代码呢?我再次仔细读题,他只需要我输出最少经过的站数,并不对每一个站是哪个站做了要求,所以一个很笨但是却思维清晰的方法浮现在我脑海中。
分析可知:
这个图就出现了。我们可以把所有的线路分成五段和两个点,总共七中情况。所以如果我穷举所有的情况也就是7*7=49种,单实际上有很多情况我们只要把起点和终点交换一下就可以作为另一种情况了。接下来下面的代码就出现了
用时:总49分钟。起始只要思路清晰一种一种情况的写是不容易出错的,虽然这个代码维护起来比较麻烦。
#include   
/* 
判断这个名字在哪段路上 
*/  
int Which(string name)  
{  
    if(name[0] == 'B')//假设name1为起点,现在只考虑起点  
    {  
        if(atoi(&name[1]) <=5 && atoi(&name[1]) >= 1)  
        {//B为第一个路段  
            return 1;  
        }  
        else if(atoi(&name[1]) <=10 && atoi(&name[1]) >= 6)  
        {  
            return 3;  
        }  
        else if(atoi(&name[1]) <=15 && atoi(&name[1]) >= 11)  
        {  
            return 5;  
        }  
    }  
    else if(name[0] == 'A')  
    {  
        if(atoi(&name[1]) <=13 && atoi(&name[1]) >= 10)  
            return 2;  
        else if((atoi(&name[1]) <=9 && atoi(&name[1]) >= 1) || (atoi(&name[1]) <=15 && atoi(&name[1]) >= 11))  
            return 4;  
    }  
    else if(name[0] == 'T')  
    {  
        if(atoi(&name[1]) == 1)  
            return 6;  
        else if(atoi(&name[1]) <=13)  
            return 7;  
    }  
    else  
        return 0;//不在这个路上的站点  
}  
  
#define T1_1(id) (6-id)     //1->T1的站数  
#define T2_1(id) (T1_1(id)+5)   //1->T2的站数  
#define T1_2(id) (id-8)     //2->T1  
#define T2_2(id) (15-id)    //2->T2  
#define T1_3(id) (id-4)     //3->T1  
#define T2_3(id) (12-id)    //3->T2  
#define T1_5(id) (6+id-10)  //5->T1  
#define T2_5(id) (id-9)     //5->T2  
//接口函数  
int BestRouting(string name1,string name2)  
{  
    //分为5段和两个节点考虑  
    //B1-B5             1     
    //A10-A13           2  
    //B6-B10            3  
    //A1-A9+A14-A18     4  
    //B11-B15           5  
    //T1                6  
    //T2                7  
    //1->(2,5,3,4)的路径很容易分析  
    int id1 = atoi(&name1[1]),id2 = atoi(&name2[1]) ;  
    if(Which(name1) == 1)//起点在1路段上  
    {  
        if(Which(name2) == 1)//都在1路段  
            return abs(id1 - id2)+1;  
        else if(Which(name2) == 2)//结束路段在2  
            return T1_1(id1)+id2-9;  
        else if(Which(name2) == 3)//借宿路段在3  
            return T1_1(id1)+id2-5;  
        else if(Which(name2) == 4)  
        {  
            if(id2 < 17)  
                return T2_1(id1)+id2-13;  
            else if(id2 == 18)  
                return T1_1(id1)+11;  
            else  
            {  
                return T1_1(id1)+10-id2;  
            }  
        }  
        else if(Which(name2) == 5)  
        {  
            return T2_1(id1)+id2-10;  
        }  
        else if(Which(name2) == 6)  
            return T1_1(id1);  
        else if(Which(name2) == 7)  
            return T2_1(id1);  
    }  
    else if(Which(name1) == 2)  
    {  
        if(Which(name2) == 1)  
            return BestRouting(name2,name1);  
        else if(Which(name2) == 2)  
            return abs(id1-id2)+1;  
        else if(Which(name2) == 3)  
        {  
            if(id1 <= 11 && id2 <= 8)  
                return T1_2(id1)+T1_3(id2)-1;  
            if(id1 >
= 12 && id2 > 8) return T2_2(id1)+T2_3(id2)-1; if(id1 <= 11 && id2 > 8) return T2_2(id1)+T2_3(id2)-1; else return T1_2(id1)+T1_3(id2)-1; } else if(Which(name2) == 4) { if(id2 >= 3 && id2 <= 9) return T1_2(id1)+10-id2; else if(id2 < 3) return T2_2(id1)+id2-1+6; else return T2_2(id1)+id2-13; } else if(Which(name2) == 5) return T2_2(id1)+id2-10; else if(Which(name2) == 6) return T1_2(id1); else if(Which(name2) == 7) return T2_2(id1); } else if(Which(name1) == 3) { if(Which(name2) == 1) return BestRouting(name2,name1); else if(Which(name2) == 2) return BestRouting(name2,name1); else if(Which(name2) == 3) return abs(id1-id2)+1; else if(Which(name2) == 4) { if(id2 >= 3 && id2 <= 9) return T1_3(id1)+10-id2; else if(id2 < 3) return T2_3(id1)+id2-1+6; else return T2_3(id1)+id2-13; } else if(Which(name2) == 5) { return id2-id1+2; } else if(Which(name2) == 6) return T1_3(id1); else if(Which(name2) == 7) return T2_3(id1); } else if(Which(name1) == 4) { if(Which(name2) == 5) { if(id2 > 5 && id2 < 14) return 15-id1+id2-10; else if(id2 <= 5) return id1+7+T2_5(id2); else return id1-13+T2_5(id2); } else if(Which(name2) == 6) { if(id1 <= 18 && id1 >= 14) return 6+id1-13; else if(id1 <= 9) return 11-id2; else return 19-id1+10; } else if(Which(name2) == 7) { if(id1 >= 5 && id1 <= 9) return 6+id1-8; else if(id1 < 5) return id1+6; else return id1 - 12; } else if(Which(name2) == 4) { if((id1 <= 9 && id1 >= 8) && (id2 <= 15 && id2 >= 14)) return 6+10-id1+id2-13; else { if(id1 <= 9 && id2 <= 9) return abs(id1-id2) + 1; else if(id1 >= 14 && id2 >= 14) return abs(id1-id2) + 1; else if(id1>id2) return 18-id1+id2+1; else if(id1 < id2) return 18-id2+id1+1; else if(id1 == id2) return 0; } } else if(Which(name2) != 0) return BestRouting(name2,name1); } else if(Which(name1) == 5) { if(Which(name2) == 6) return T1_5(id1); else if(Which(name2) == 7) return T2_5(id1); else if(Which(name2) != 0) return BestRouting(name2,name1); } else if(Which(name1) == 6) { if(Which(name2) == 6) return 0; else if(Which(name2) == 7) return 6; else if(Which(name2) != 0) return BestRouting(name2,name1); } else if(Which(name1) == 7) { if(Which(name2) == 7 return 0; if(Which(name2) != 0) return BestRouting(name2,name1); } return -1; } int main(int argc, char* argv[]) { cout<

这件事给我的感触挺深的,我想起我曾经一个老师怎么教我们 编程的。她说过,永远没有最好的代码与最差的代码,永远是适合最好。我相信很多人绝对会觉得这个代码就是一个刚学几条语法的新手编出来的,但是这种新手代码在华为的考场上绝对能帮到你很大的忙。
当然,这个方法对于这种结构简单情况讨论清晰的题来是很好的,但是对于复杂的结构肯定就不能用这种方法了。
如果大家有更好的方法,希望大神教教我,谢谢。