WOJ 51 Bus Route Problem题解

这篇博客介绍了一个帮助优化公交查询系统的问题,需要找到从起点到终点包含最多4辆公交车的最少站数路线。程序员可以使用回溯法解决这个问题,通过构建以车站为节点、公交车号和下一站为边的图来实现。样例输入和输出展示了算法的正确性,每个有效路线按站数、公交车数量和字母顺序排列。
摘要由CSDN通过智能技术生成

题目

Dongfang, A hardworking student, last week, he made the software named Query bus route system in WuHan, but he met a very intractability
problem At first, he tried to solve it by algorithm he had learned last summer, but it’s not appropriate for the MIS (Management
Information System). However, the function of the system has declined a lot if he used the database initial function. Now, you are
an excellent programmer, it is your task to help DongFang to improve the function of the software.
Assuming that there are n stations, whose names are the first n letters of the set{A, B, C, ? , Z, a, b, c, ?, z}. And in daily life,
to pay less fee, we often choose a bus route which contains D (1<=D<=4) buses at the most.

输入格式
An integer T (0 < T < 20) at the first line of the file represents the number of cases. In each case, it begins with three integers m(1<=m<=50),
n(2<=n<=52), D, representing that there is m buses, n stations and the maximum number of buses that a route can contains. Then m lines,
each line begins with two integers k(1<=k<=m) and l, followed by l letters; each letter means the bus k can pass this station.
In the last line, there are two letters x and y, denoting the starting station and the destination.

输出格式
Each case begins with (case i:),?i? is counted from 1,and each case ends with ?There are P routes in total!?, P is the number of
total routes from starting station to end station.
All of the P routes should be output in the following rules. First, the routes should be ordered by the number of stations. Second, if number of buses in two routes is the same, you should output the routes in the lexical order. Third, if two route?s stations are the same, the route whose first bus number is smaller should be output before the other one, if it is also the same, then see the next bus number??
The route?s first station must be the starting one, and the last station must be the end station. And the stations of the route should be different from each other.
The format of the route should as follows: A 1 B 2 C It means from starting station A, you take bus 1, on arriving at the station B, you take the bus 2, finally arrive at the destination C. There is a blank line between two neighboring case, in each case, each route should be output in separated line.

样例输入
1
3 3 4
1 2 A B
2 3 B A C
3 1 A
A C
样例输出
case 1:
A 2 C
A 1 B 2 C
A 2 B 2 C
There are 3 routes in total!

解析

注意两个case输出之间有个空行。。。我就是忘了这个一直没提交通过😅
简单的回溯法,即可解决,注意数据结构的设计,我这边是把车站作为节点,以公交车号和下一站作为边的信息 来构图。理解题意的时候,注意一个巴士能经过的站都能两两直达就行了。

代码

#include<iostream>
#include<vector>
#include <unordered_map>

#include <algorithm>


using namespace std;

int m, n, D;
char start, terminal;

void backtrack(vector<vector<pair<int, char>>>& result, vector<pair<int, char>>& route, unordered_map<char, vector<pair<int, char>>>& stations, char curStation) {
    if (route.size() > D) {
        return;
    }
    if (curStation == terminal) {
        result.push_back(route);
        return;
    } else {
        for (auto &next : stations[curStation]) {
            bool flag = false;
            for (auto &sta : route) { // station should be different
                if (sta.second == next.second) {
                    flag = true;
                    break;
                }
            }
            if (flag) {
                continue;
            }
            if (next.second == start) {
                continue;
            }
            route.emplace_back(next.first, next.second);
            backtrack(result, route, stations, next.second);
            route.pop_back();
        }
    }
}

int main() {
    int t, caseNum = 0;
    cin >> t;
    while (caseNum++ < t) {
        cin >> m >> n >> D; // m bus, n stations, maximum D station each route contains
        // 临接表图
        unordered_map<char, vector<pair<int, char>>> stations; //

        int busNum, staNum;

        for (int i = 0; i < m; ++i) {
            cin >> busNum >> staNum;
            vector<char> staPass(staNum);
            for (int j = 0; j < staNum; ++j) {
                cin >> staPass[j];
            }
            // 两两直达
            for (int j = 0; j < staNum - 1; ++j) {
                for (int k = j+1; k < staNum; ++k) {
                    stations[staPass[j]].push_back(make_pair(busNum, staPass[k]));
                    stations[staPass[k]].push_back(make_pair(busNum, staPass[j]));
                }
            }
        }
        cin >> start >> terminal;
        vector<pair<int, char>> route;
        vector<vector<pair<int, char>>> result;

        backtrack(result, route, stations, start);

        std::sort(result.begin(), result.end(), [](vector<pair<int, char>>& r1, vector<pair<int, char>>& r2){
            if (r1.size() < r2.size()) {
                return true;
            } else if (r1.size() > r2.size()){
                return false;
            } else { // 经过的车站数相等
                for (int i = 0; i < r1.size(); ++i) { // 车站字母顺序
                    if (r1[i].second != r2[i].second) {
                        return r1[i].second < r2[i].second;
                    }
                }
                for (int i = 0; i < r1.size(); ++i) { // 公交车顺序
                    if (r1[i].first != r2[i].first) {
                        return r1[i].first < r2[i].first;
                    }
                }
                return true;
            }
        });

        if (caseNum != 1) {
            cout << endl;
        }
        cout << "case " << caseNum << ":\n";
        for(auto& ro : result) {
            cout << start;
            for (auto& sta : ro) {
                cout << " " << sta.first << " " << sta.second;
            }
            cout << endl;
        }
        cout << "There are " << result.size() << " routes in total!" << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值