2013年“中兴捧月”杯校园程序设计大赛复赛任务二解答

一、设计方案

复赛增加了一个条件,也正是这个条件提升了问题的难度。诸如BFS等最短路径算法均不能求解经过指定顶点的最短路径。虽然如此,但是可以考虑将这个问题转换为求解最短路径问题。

首先计算sd的最短路径,如果包含了所有的中间节点,显然这就是符合条件的最优解了。如果没有找到最短路径,说明不存在一条路径。比较复杂的情况是找到了最短路径,但是没有包含所有中间节点。

如果只有一个中间节点m,可以将路径从中间节点处分为两段。分别求两段的最短路径,如果两段最短路径除了m外没有公共节点,那么合并这两段路径可以得到最优解。两段有除了m外的其它公共点就先计算其中一段路径的最短路径,从图上去掉这个路径所包含的节点,然后再求第二段路径,合并可以得到一条从sd经过m的路径。两次计算可以求得sd经过m的最短路径。

如果包含多个中间节点就更为复杂了。这种情况下,考虑计算经过其中一个中间节点的路径。如果不存在经过某个节点的路径那么就不存在解。如果某条路径包含了所有节点,那么这条路径是一个解。求出来所有这样的解,其中的最短路径是最优解。如果不存在某条路径包含了所有的中间节点,那么可以知道,从sd经过每一个中间点都存在一条路径,在这种情况下,可以遍历m1,m2,…,mn依次求解s->m1->…->ds->m2->…->d等,最后求得满足条件的最短路径,但这样获得的路径不能保证是最短路径。

如果以上方法均不能求得结果,那么只有祭出最强神器——深度优先搜索。深度优先搜索能够遍历所有路径,可以获得符合要求的最短路径。虽然能够求得最优解,但是时间复杂度较高,在边数较少的情况下可以快速求得解。为了能在10分钟内得到解,在计算的过程中检查是否超时。

二、性能

本程序中,bfs的时间复杂度是O(E+V),其中E是边数,V是节点数,解决问题需要调用O(N²)bfs(虽然最后采用dfs来保底,但是主要是以bfs来解决问题的),其中N为中间点数目,总的运行时间是O((E+V)N²)

首先,使用示例数据进行测试。

zte.exe /fin.txt /oout.txt /s20 /d32 /m"22,23"

示例问题解决时间小于1秒。

下面增加几个点,并且打乱点的顺序。如

zte.exe /fin.txt /oout.txt /s8 /d46 /m"37,31,47,48,39,22,23,20,45,24,32"

这个问题有11个中间节点,解决时间小于1,可以得到路径“main: 8, 45, 37, 29, 20, 21, 22, 23, 24, 32, 31, 30, 39, 4, 48, 47, 46”。

然后,本人写了个程序用于生成一个图,图的节点有5000个,边数总计有12158条。

先在5000个节点上求解几个点。如

zte.exe /ftest.txt /oout.txt /s1 /d5000 /m"2,3,4,5,6"

解决这个问题的时间小于1秒。计算得到的路径为main: 1, 35, 25, 31, 5, 2, 41, 42, 6, 3, 46, 22, 4, 50, 92, 89, 135, 179, 201, 239, 287, 336, 376, 407, 428, 458, 503, 551, 599, 644, 682, 721, 764, 806, 830, 858, 892, 940, 989, 1024, 1068, 1110, 1156, 1205, 1228, 1274, 1318, 1343, 1381, 1426, 1474, 1518, 1540, 1583, 1620, 1653, 1679, 1723, 1767, 1816, 1855, 1902, 1949, 1981, 2023, 2072, 2114, 2130, 2174, 2214, 2260, 2305, 2354, 2403, 2429, 2462, 2505, 2548, 2590, 2616, 2664, 2699, 2744, 2774, 2807, 2855, 2894, 2932, 2957, 2998, 3041, 3087, 3128, 3165, 3214, 3243, 3289, 3322, 3368, 3417, 3466, 3494, 3540, 3586, 3634, 3659, 3699, 3744, 3793, 3840, 3881, 3893, 3941, 3989, 4034, 4069, 4104, 4132, 4178, 4225, 4258, 4303, 4330, 4359, 4408, 4447, 4496, 4537, 4573, 4616, 4662, 4706, 4747, 4772, 4806, 4855, 4892, 4918, 4954, 5000

这条路径有139个节点,下面去掉起始节点和目的节点,然后打乱路径其它节点的顺序,再求解问题,如下

zte.exe /ftest.txt /oout.txt /s1 /d5000 /m"4258,4303,4330,4359,4408,407,428,458,503,551,599,644,682,721,764,806,830,858,892,940,989,1024,1068,35,25,31,5,2,2174,2214,2260,2305,2354,2403,2429,2462,2505,2548,2590,41,42,6,3,46,22,4,50,92,2616,2664,2699,2744,2774,2807,2855,2894,2932,2957,2998,3041,3087,3128,3165,3214,3243,3289,3322,3368,3417,3466,3494,3540,3586,3634,3659,3699,3744,3793,3840,3881,3893,3941,3989,4034,4069,4104,4132,4178,4225,1110,1156,1205,1228,1274,1318,1343,1381,1426,1474,1518,1540,1583,1620,1653,1679,1723,1767,4447,4496,4537,4573,4616,4662,4706,4747,4772,4806,4855,4892,4918,4954,89,135,179,201,239,287,336,376,1816,1855,1902,1949,1981,2023,2072,2114,2130"

虽然没有得到最优解,但是这个问题5秒内可以解决。得到的路径为“main: 1, 35, 76, 106, 155, 179, 201, 239, 287, 336, 376, 407, 428, 458, 503, 551, 599, 644, 682, 721, 764, 806, 830, 858, 892, 940, 989, 1024, 1068, 1110, 1156, 1205, 1228, 1274, 1318, 1343, 1381, 1426, 1474, 1518, 1540, 1583, 1620, 1653, 1679, 1723, 1767, 1816, 1855, 1902, 1949, 1981, 2023, 2072, 2114, 2130, 2174, 2214, 2260, 2305, 2354, 2403, 2429, 2462, 2505, 2548, 2590, 2616, 2664, 2699, 2744, 2774, 2807, 2855, 2894, 2932, 2957, 2998, 3041, 3087, 3128, 3165, 3214, 3243, 3289, 3322, 3368, 3417, 3466, 3494, 3540, 3586, 3634, 3659, 3699, 3744, 3793, 3840, 3881, 3893, 3941, 3989, 4034, 4069, 4104, 4132, 4178, 4225, 4258, 4303, 4330, 4359, 4408, 4379, 4342, 4331, 4301, 4269, 4230, 4181, 4141, 4099, 4050, 4010, 3965, 3921, 3884, 3836, 3814, 3768, 3729, 3691, 3650, 3607, 3575, 3526, 3501, 3462, 3428, 3389, 3353, 3304, 3287, 3238, 3189, 3145, 3103, 3064, 3053, 3032, 2990, 2942, 2904, 2873, 2838, 2792, 2769, 2726, 2697, 2657, 2634, 2593, 2547, 2503, 2461, 2417, 2394, 2363, 2317, 2289, 2242, 2208, 2172, 2138, 2090, 2045, 2002, 1963, 1922, 1899, 1858, 1830, 1782, 1739, 1691, 1666, 1627, 1602, 1555, 1517, 1498, 1453, 1405, 1392, 1345, 1297, 1255, 1217, 1184, 1168, 1120, 1073, 1032, 986, 962, 927, 888, 839, 797, 755, 729, 688, 643, 628, 591, 550, 507, 485, 439, 401, 364, 316, 276, 236, 187, 149, 126, 102, 68, 25, 31, 5, 2, 41, 42, 6, 3, 46, 22, 4, 50, 92, 89, 135, 151, 197, 226, 271, 318, 360, 386, 434, 472, 493, 536, 576, 620, 658, 700, 706, 743, 785, 831, 867, 899, 944, 984, 1009, 1036, 1084, 1121, 1161, 1203, 1250, 1296, 1298, 1344, 1389, 1411, 1441, 1488, 1512, 1556, 1590, 1639, 1677, 1725, 1773, 1815, 1845, 1888, 1920, 1951, 1998, 2047, 2049, 2098, 2137, 2186, 2231, 2268, 2308, 2341, 2374, 2423, 2442, 2487, 2527, 2573, 2598, 2622, 2661, 2700, 2737, 2779, 2809, 2848, 2869, 2907, 2956, 2989, 3035, 3080, 3089, 3131, 3153, 3169, 3215, 3242, 3268, 3314, 3347, 3394, 3440, 3487, 3499, 3546, 3573, 3618, 3667, 3712, 3761, 3772, 3819, 3839, 3878, 3923, 3972, 4003, 4039, 4077, 4116, 4146, 4186, 4229, 4266, 4307, 4336, 4384, 4429, 4447, 4496, 4537, 4573, 4616, 4662, 4706, 4747, 4772, 4806, 4855, 4892, 4918, 4954, 5000”。

再把这个路径打乱,继续求解。

zte.exe /ftest.txt /s1 /d5000 /m"35,76,106,155,179,201,239,287,336,376,407,428,458,503,551,599,644,682,721,764,806,830,858,892,940,989,1024,1068,1110,1156,1205,1228,1274,1318,1343,1381,1426,1474,1518,1540,1583,1620,1653,1679,1723,1767,1816,1855,1902,1949,1981,2023,2072,2114,2130,2174,2214,2260,2305,2354,2403,2429,2462,2505,2548,2590,2616,2664,2699,2744,2774,2807,2855,2894,2932,2957,2998,3041,3087,3128,3165,3214,3243,3289,3322,3368,3417,3466,3494,3540,3586,3634,3659,3699,439,401,364,316,276,236,187,149,126,102,68,25,31,5,2,41,42,6,3,46,22,4,50,92,89,135,151,197,226,271,318,360,386,434,472,493,536,576,620,658,700,706,743,785,831,867,899,944,984,1009,1036,1084,1121,1161,1203,1250,1296,1298,1344,1389,1411,1441,1488,1512,1556,1590,1639,1677,1725,1773,1815,1845,1888,1920,1951,1998,2047,2049,2098,2137,2186,2231,2268,2308,2341,2374,2423,2442,2487,2527,2573,2598,2622,2661,2700,2737,2779,2809,2848,2869,2907,2956,2989,3035,3080,3089,3131,3153,3169,3215,3242,3268,3314,3347,3394,3440,3487,3499,3546,3573,3618,3667,3712,3761,3772,3819,3839,3878,3923,3972,4003,4039,4077,4116,4146,4186,4229,4266,4307,4336,4384,4429,4447,4496,4537,4573,4616,4662,4706,4747,4772,4806,4855,4892,4918,4954,3744,3793,3840,3881,3893,3941,3989,4034,4069,4104,4132,4178,4225,4258,4303,4330,4359,4408,4379,4342,4331,4301,4269,4230,4181,4141,4099,4050,4010,3965,3921,3884,3836,3814,3768,3729,3691,3650,3607,3575,3526,3501,3462,3428,3389,3353,3304,3287,3238,3189,3145,3103,3064,3053,3032,2990,2942,2904,2873,2838,2792,2769,2726,2697,2657,2634,2593,2547,2503,2461,2417,2394,2363,2317,2289,2242,2208,2172,2138,2090,2045,2002,1963,1922,1899,1858,1830,1782,1739,1691,1666,1627,1602,1555,1517,1498,1453,1405,1392,1345,1297,1255,1217,1184,1168,1120,1073,1032,986,962,927,888,839,797,755,729,688,643,628,591,550,507,485"

虽然有373个中间点,但是只用了两分钟便得到了解,而且求得的解与打乱前的路径是同一条路径,这里不再列出。

三、代码

//----------------------------------------------------------------------

// 需要包含的头文件和使用的命名空间。

//----------------------------------------------------------------------

#include <iostream>

#include <fstream>

#include <list>

#include <queue>

#include <cstdlib>

#include <string>

#include <bitset>

#include <ctime>

#include <windows.h>

using namespace std;

 

//----------------------------------------------------------------------

// 节点数目和最大节点数目。

//----------------------------------------------------------------------

int V = 0;

time_t timer;

const int NODE_SIZE = 5001;

 

//----------------------------------------------------------------------

// 检查是否超时。

//----------------------------------------------------------------------

bool timeout()

{

    time_t cur;

    return (time(&cur) - timer) > 600;

}

 

//----------------------------------------------------------------------

// 使用广度优先搜索算法求解最优路径。

//----------------------------------------------------------------------

void bfs(int graph[NODE_SIZE][NODE_SIZE], int snode, int dnode,

    int road[NODE_SIZE])

{

    //------------------------------------------------------------------

    // 如果超时不再继续搜索。

    //------------------------------------------------------------------

    if (timeout()) {

        return;

    }

 

    //------------------------------------------------------------------

    // 标识和前驱。

    //------------------------------------------------------------------

    static int flag[NODE_SIZE], prev[NODE_SIZE];

 

    //------------------------------------------------------------------

    // 初始化数据。

    //------------------------------------------------------------------

    for (int i = 0; i <= V; i++) {

        flag[i] = 0;

        prev[i] = 0;

    }

   

    //------------------------------------------------------------------

    // 广度优先搜索算法。

    //------------------------------------------------------------------

    int beg = 0, end = 1;

    static int qarray[NODE_SIZE];

    flag[dnode] = 1;

    qarray[0] = dnode;

    while (beg != end) {

        int t = qarray[beg];

        for (int i = 1; i <= graph[t][0]; i++) {

            int element = graph[t][i];

            if (flag[element] == 0) {

                prev[element] = t;

                flag[element] = 1;

                qarray[end++] = element;

            }

        }

        beg++;

    }

 

    //------------------------------------------------------------------

    // 通过前驱获得路径。

    //------------------------------------------------------------------

    if (prev[snode]) {

        int element = snode;

        road[0] = 1;

        road[1] = element;

        while (dnode != element) {

            element = prev[element];

            road[++road[0]] = element;

        }

    }

}

 

//----------------------------------------------------------------------

// 去掉某条路径后再求解最优路径。

//----------------------------------------------------------------------

void bfs_cond(int graph[NODE_SIZE][NODE_SIZE], int snode, int dnode,

    int cond[NODE_SIZE], int road[NODE_SIZE])

{

    //------------------------------------------------------------------

    // 去掉指定路径。

    //------------------------------------------------------------------

    for (int i = 1; i <= cond[0]; i++) {

        int cur = cond[i];

        if (cur != snode && cur != dnode) {

            graph[cur][0] = -graph[cur][0];

        }

    }

 

    //------------------------------------------------------------------

    // 求得最优解。

    //------------------------------------------------------------------

    bfs(graph, snode, dnode, road);

 

    //------------------------------------------------------------------

    // 恢复指定路径。

    //------------------------------------------------------------------

    for (int i = 1; i <= cond[0]; i++) {

        int cur = cond[i];

        if (cur != snode && cur != dnode) {

            graph[cur][0] = -graph[cur][0];

        }

    }

}

 

//----------------------------------------------------------------------

// 路径是否包含所有中间节点。

//----------------------------------------------------------------------

bool has_all_mnode(int road[NODE_SIZE], int mnode[NODE_SIZE])

{

    static int flag[NODE_SIZE];

 

    for (int i = 0; i <= V; i++) {

        flag[i] = 0;

    }

 

    for (int i = 1; i <= road[0]; i++) {

        flag[road[i]] = 1;

    }

 

    for (int i = 1; i <= mnode[0]; i++) {

        if (!flag[mnode[i]]) {

            return false;

        }

    }

 

    return true;

}

 

//----------------------------------------------------------------------

// 使用深度优先搜索算法求解最优路径。

//----------------------------------------------------------------------

void dfs(int graph[NODE_SIZE][NODE_SIZE], int snode, int dnode,

    int temp[NODE_SIZE], int htab[NODE_SIZE], int mnode[NODE_SIZE],

    int road[NODE_SIZE])

{

    //------------------------------------------------------------------

    // 如果超时不再继续搜索。

    //------------------------------------------------------------------

    if (timeout() || road[0] == mnode[0] + 2) {

        return;

    }

 

    //------------------------------------------------------------------

    // s等于d说明搜索到了目标。

    //------------------------------------------------------------------

    htab[snode] = 1;

    temp[++temp[0]] = snode;

    if (snode == dnode) {

        if (has_all_mnode(temp, mnode)) {

            if (road[0] == 0 || road[0] > temp[0]) {

                road[0] = temp[0];

                for (int j = 1; j <= temp[0]; j++) {

                    road[j] = temp[j];

                }

            }

        }

        htab[snode] = 0;

        temp[0]--;

        return;

    }

 

    //------------------------------------------------------------------

    // 遍历所有路径。

    //------------------------------------------------------------------

    for (int i = 1; i <= graph[snode][0]; i++) {

        if (htab[graph[snode][i]] != 1) {

            dfs(graph, graph[snode][i], dnode, temp, htab, mnode, road);

        }

    }

 

    //------------------------------------------------------------------

    // 遍历所有路径。

    //------------------------------------------------------------------

    temp[0]--;

    htab[snode] = 0;

}

 

//----------------------------------------------------------------------

// 使用深度优先搜索算法求解最优路径。

//----------------------------------------------------------------------

void dfs(int graph[NODE_SIZE][NODE_SIZE], int snode, int dnode,

    int mnode[NODE_SIZE], int road[NODE_SIZE])

{

    static int temp[NODE_SIZE];

    static int htab[NODE_SIZE];

    road[0] = 0;

    for (int i = 0; i <= V; i++) {

        htab[i] = 0;

    }

    dfs(graph, snode, dnode, temp, htab, mnode, road);

}

 

//----------------------------------------------------------------------

// 合并两条顺序连接的路径。

//----------------------------------------------------------------------

void append_path(int road[NODE_SIZE], int tail[NODE_SIZE])

{

    for (int i = 1, j = road[0]; i <= tail[0]; i++, j++) {

        road[j] = tail[i];

    }

 

    road[0] = road[0] + tail[0] - 1;

}

 

//----------------------------------------------------------------------

// 合并两条以中间节点为起点的路径。

//----------------------------------------------------------------------

void form_path(int a[NODE_SIZE], int b[NODE_SIZE], int road[NODE_SIZE])

{

    road[0] = a[0] + b[0] - 1;

 

    for (int i = a[0], j = 1; i >= 1; i--, j++) {

        road[j] = a[i];

    }

 

    for (int i = 1, j = a[0]; i <= b[0]; i++, j++) {

        road[j] = b[i];

    }

}

 

//----------------------------------------------------------------------

// 查看节点是否在路径中。

//----------------------------------------------------------------------

bool is_node_in_path(int node, int road[NODE_SIZE])

{

    for (int i = 1; i <= road[0]; i++) {

        if (road[i] == node) {

            return true;

        }

    }

    return false;

}

 

//----------------------------------------------------------------------

// 根据条件查找源节点和目的节点之间包含单个中间节点的路径。

//----------------------------------------------------------------------

void solve_with_node_1(int graph[NODE_SIZE][NODE_SIZE], int snode,

    int dnode, int mnode, int road[NODE_SIZE])

{

    //------------------------------------------------------------------

    // 找出以m到s、d的最短路径,其中一条路径不存在则满足条件的路径也不

    // 存在,两条路径无共同点则拼接可得最优解,有共同点则穷举求得路径。

    //------------------------------------------------------------------

    static int r1[NODE_SIZE], r2[NODE_SIZE];

    road[0] = 0;

    bfs(graph, mnode, snode, r1);

    bfs(graph, mnode, dnode, r2);

 

    //------------------------------------------------------------------

    // 其中一条路径不存在则满足条件的路径也不存在。

    //------------------------------------------------------------------

    if (r1[0] <= 0 || r2[0] <= 0) {

        return;

    }

 

    //------------------------------------------------------------------

    // 两条路径无共同点则拼接可得最优解。

    //------------------------------------------------------------------

    if (r1[1] != r2[1]) {

        form_path(r1, r2, road);

        return;

    }

 

    //------------------------------------------------------------------

    // 有共同点则先去除一段路径后再求解另一段路径。

    //------------------------------------------------------------------

    static int r12[NODE_SIZE], r21[NODE_SIZE];

    bfs_cond(graph, mnode, dnode, r1, r12);

    bfs_cond(graph, mnode, snode, r2, r21);

 

    //------------------------------------------------------------------

    // 比较路径,取最优路径。

    //------------------------------------------------------------------

    if (r12[0] > 0) {

        if (r21[0] > 0) {

            if (r1[0] + r12[0] < r2[0] + r21[0]) {

                form_path(r1, r12, road);

            } else {

                form_path(r21, r2, road);

            }

        } else {

            form_path(r1, r12, road);

        }

    } else {

        if (r21[0] > 0) {

            form_path(r21, r2, road);

        }

    }

}

 

//----------------------------------------------------------------------

// 根据条件查找源节点和目的节点之间包含多个中间节点的路径。

//----------------------------------------------------------------------

void solve_with_node_X(int graph[NODE_SIZE][NODE_SIZE], int snode,

    int dnode, int mnode[NODE_SIZE], int road[NODE_SIZE])

{

    //------------------------------------------------------------------

    // 如果通过某个节点的路径包含了所有中间节点,那么得到解,取其中最短

    // 的路径,如果不存在通过某个中间节点的路径,那么不存在解。

    //------------------------------------------------------------------

    road[0] = 0;

    for (int i = 1; i <= mnode[0]; i++) {

        static int temp[NODE_SIZE];

        solve_with_node_1(graph, snode, dnode, mnode[i], temp);

        if (temp[0] <= 0) {

            return;

        }

        if (has_all_mnode(temp, mnode)) {

            if (road[0] == 0 || road[0] > temp[0]) {

                road[0] = temp[0];

                for (int j = 1; j <= temp[0]; j++) {

                    road[j] = temp[j];

                }

                if (road[0] == mnode[0] + 2) {

                    return;

                }

            }

        }

    }

 

    //------------------------------------------------------------------

    // 上面若能得到解肯定是最优解。

    //------------------------------------------------------------------

    if (road[0] > 0) {

        return;

    }

 

    //------------------------------------------------------------------

    // 依次遍历s->m1->...->d,s->m2->...->d,到s->mn->...->d。

    //------------------------------------------------------------------

    for (int i = 1; i <= mnode[0]; i++) {

        static int rsmy[NODE_SIZE];

        bfs(graph, snode, mnode[i], rsmy);

        if (rsmy[0] > 0) {

            //----------------------------------------------------------

            // 搜索路径s->mX->...->mY。

            //----------------------------------------------------------

            int node = mnode[i];

            for (int j = 1; j <= mnode[0]; j++) {

                if (!is_node_in_path(mnode[j], rsmy)) {

                    int tnode;

                    static int rm2m[NODE_SIZE];

                    tnode = mnode[j];

                    rsmy[++rsmy[0]] = dnode;

                    bfs_cond(graph, node, tnode, rsmy, rm2m);

                    rsmy[0]--;

                    if (rm2m[0] <= 0) {

                        node = -1;

                        break;

                    }

                    append_path(rsmy, rm2m);

                    node = tnode;

                }

            }

 

            if (node != -1) {

                //------------------------------------------------------

                // 搜索路径mY->d。

                //------------------------------------------------------

                static int rmyd[NODE_SIZE];

                bfs_cond(graph, node, dnode, rsmy, rmyd);

                if (rmyd[0] > 0) {

                    append_path(rsmy, rmyd);

                    //--------------------------------------------------

                    // 保存搜索到的最短路径。

                    //--------------------------------------------------

                    if (road[0] == 0 || road[0] > rsmy[0]) {

                        road[0] = rsmy[0];

                        for (int j = 1; j <= rsmy[0]; j++) {

                            road[j] = rsmy[j];

                        }

                        if (road[0] == mnode[0] + 2) {

                            return;

                        }

                    }

                }

            }

        }

    }

 

    //------------------------------------------------------------------

    // 如果找到了路径就返回吧,虽然这里找到的不一定是最优的。

    //------------------------------------------------------------------

    if (road[0] > 0) {

        return;

    }

 

    //------------------------------------------------------------------

    // 如果还是找不到,那么只有祭出最强法宝——深度优先搜索。

    //------------------------------------------------------------------

    dfs(graph, snode, dnode, mnode, road);

}

 

//----------------------------------------------------------------------

// 根据条件查找源节点和目的节点之间的路径。

//----------------------------------------------------------------------

int solve(const char *iname, const char *oname, int snode, int dnode,

    int mnode[NODE_SIZE])

{

    //------------------------------------------------------------------

    // 图的邻接矩阵。

    //------------------------------------------------------------------

    static int graph[NODE_SIZE][NODE_SIZE];

 

    //------------------------------------------------------------------

    // 清空图。

    //------------------------------------------------------------------

    for (int i = 0; i < NODE_SIZE; i++)

        for (int j = 0; j < NODE_SIZE; j++)

            graph[i][j] = 0;

   

    //------------------------------------------------------------------

    // 从输入文件读取图。

    //------------------------------------------------------------------

    ifstream ifs(iname);

    if (ifs.is_open()) {

        int a, b;

        string title;

        getline(ifs, title);

        while (!ifs.eof()) {

            char c;

            ifs >> a >> c >> b;

            graph[a][++graph[a][0]] = b;

            graph[b][++graph[b][0]] = a;

            V = V < a ? a : (V < b ? b : V);

        }

        ifs.close();

    } else {

        return -1;

    }

   

    //------------------------------------------------------------------

    // 路径。

    //------------------------------------------------------------------

    static int road[NODE_SIZE];

 

    //------------------------------------------------------------------

    // 搜索符合条件的路径。

    //------------------------------------------------------------------

    if (mnode[0] <= 0)

    {

        //--------------------------------------------------------------

        // 如果没有中间节点就求s到d的最短路径。

        //--------------------------------------------------------------

        bfs(graph, snode, dnode, road);

    }

    else

    {

        //--------------------------------------------------------------

        // 如果s到d的没有路径就不用继续了。

        //--------------------------------------------------------------

        bfs(graph, snode, dnode, road);

        if (road[0] > 0)

        {

            //----------------------------------------------------------

            // 如果搜索到的路径包含了所有中间节点,那么这就是最优解,其

            // 它情况下用一般的方法求解。

            //----------------------------------------------------------

            if (!has_all_mnode(road, mnode)) {

                road[0] = 0;

                solve_with_node_X(graph, snode, dnode, mnode, road);

            }

        }

    }

   

    //------------------------------------------------------------------

    // 输出结果。

    //------------------------------------------------------------------

    ofstream ofs(oname);

    if (ofs.is_open()) {

        ofs << "main:";

        for (int i = 1; i <= road[0]; i++) {

            ofs << " " << road[i];

            if (i != road[0])

                ofs << ",";

        }

        ofs << endl;

       

    } else {

        return -1;

    }

   

    //------------------------------------------------------------------

    // 完成。

    //------------------------------------------------------------------

    return 0;

}

 

//----------------------------------------------------------------------

// 从字符串中获取中间节点列表。

//----------------------------------------------------------------------

void get_mnode_list(const char *str, int mnode[NODE_SIZE])

{

    mnode[0] = 0;

 

    while (*str)

    {

        while (*str == ',') str++;

        mnode[++mnode[0]] = atoi(str);

        while (*str >= '0' && *str <= '9') str++;

    }

}

 

//----------------------------------------------------------------------

// 程序入口,argc是命令行参数个数,argv是命令行参数表。

//----------------------------------------------------------------------

int main(int argc, char **argv)

{

    //------------------------------------------------------------------

    // 默认的输入文件、输出文件、源节点、目的节点、约束条件等参数。

    //------------------------------------------------------------------

    int snode = -1;                     // 默认源节点

    int dnode = -1;                     // 默认目的节点

    int mnode[NODE_SIZE];               // 中间节点列表

    const char *iname = "in.txt";       // 默认输入文件

    const char *oname = "out.txt";      // 默认输出文件

 

    //------------------------------------------------------------------

    // 保存程序开始运行时的时间。

    //------------------------------------------------------------------

    timer = time(&timer);

   

    //------------------------------------------------------------------

    // 根据命令行参数确定输入文件、输出文件、源节点、目的节点、约束条件

    // 等参数。

    //------------------------------------------------------------------

    while (*argv) {

        char *str = *argv++;

        if (*str++ == '/') {

            switch (*str++) {

            case 'f':

            case 'F':

                if (*str) {

                    iname = str;

                } else {

                    iname = *argv++;

                }

                break;

            case 's':

            case 'S':

                if (*str) {

                    snode = atoi(str);

                } else {

                    snode = atoi(*argv++);

                }

                break;

            case 'd':

            case 'D':

                if (*str) {

                    dnode = atoi(str);

                } else {

                    dnode = atoi(*argv++);

                }

                break;

            case 'm':

            case 'M':

                if (*str) {

                    get_mnode_list(str, mnode);

                } else {

                    get_mnode_list(*argv++, mnode);

                }

                break;

            case 'o':

            case 'O':

                if (*str) {

                    oname = str;

                } else {

                    oname = *argv++;

                }

                break;

            default:

                break;

            }

        }

    }

   

    //------------------------------------------------------------------

    // 调用solve函数解决问题。

    //------------------------------------------------------------------

    return solve(iname, oname, snode, dnode, mnode);

}


你可能感兴趣的:(2013年“中兴捧月”杯校园程序设计大赛复赛任务二解答)