// Tourist Guide (导游) // PC/UVa IDs: 111006/10199, Popularity: B, Success rate: average Level: 3 // Verdict: Accepted // Submission Date: 2011-10-07 // UVa Run Time: 0.040s // // 版权所有(C)2011,邱秋。metaphysis # yeah dot net // // [Problem Description] // Rio de Janeiro is a very beautiful city, but there are so many places to visit // that you feel overwhelmed, Fortunately, your friend Bruno has promised to be // your tour guide. // // Unfortunately, Bruno is terrible driver. He has a lot of traffic fines to pay // and is eager to avoid paying more. Therefore he wants to know where all the // police cameras are located so he can drive more carefully when passing by them. // These cameras are strategically distributed over the city, in locations that // a driver must pass through in order to travel from one zone of the city to // another. A location C will have a camera if and only if there are two city // locations A and B such that all paths from A to B pass through a location C. // // For instance, suppose that we have six locations (A, B, C, D, E, and F ) with // seven bidirectional routes B − C, A − B, C − A, D − C, D − E, E − F , and F − C. // There must be a camera on C because to go from A to E you must pass through C. // In this configuration, C is the only camera location. // // Given a map of the city, help Bruno avoid further fines during your tour by // writing a program to identify where all the cameras are. // // [Input] // The input will consist of an arbitrary number of city maps, where each map // begins with an integer N (2 < N ≤ 100) denoting the total number of locations // in the city. Then follow N different place names at one per line, where each // place name will consist of least one and at most 30 lowercase letters. A // non-negative integer R then follows, denoting the total routes of the city. // The next R lines each describe a bidirectional route represented by the two // places that the route connects. // // Location names in route descriptions will always be valid, and there will be // no route from one place to itself. You must read until N = 0, which should not // be processed. // // [Output] // For each city map you must print the following line: // // City map #d: c camera(s) found // // where d stands for the city map number (starting from 1) and c stands for the // total number of cameras. Then should follow c lines with the location names // of each camera in alphabetical order. Print a blank line between output sets. // // [Sample Input] // 6 // sugarloaf // maracana // copacabana // ipanema // corcovado // lapa // 7 // ipanema copacabana // copacabana sugarloaf // ipanema sugarloaf // maracana lapa // sugarloaf maracana // corcovado sugarloaf // lapa corcovado // 5 // guanabarabay // downtown // botanicgarden // colombo // sambodromo // 4 // guanabarabay sambodromo // downtown sambodromo // sambodromo botanicgarden // colombo sambodromo // 0 // // [Sample Output] // City map #1: 1 camera(s) found // sugarloaf // // City map #2: 1 camera(s) found // sambodromo // // [解题方法] // 摄像头的位置对应图论的割顶(articulation vertex)概念,求图的割顶即可,需要注意的是,测试数 // 据所给的可能不是连通图,故需要找到其中的所有连通子图的割顶。 #include <iostream> #include <cstring> #include <vector> #include <algorithm> #include <queue> #include <map> using namespace std; #define MAXV 100 string locations[MAXV + 1]; int edges[MAXV + 1][MAXV + 1]; int degree[MAXV + 1]; int nvertices; bool discovered[MAXV + 1]; // 深度优先遍历。 void dfs(int start) { discovered[start] = true; nvertices++; for (int i = 0; i < degree[start]; i++) if (discovered[edges[start][i]] == false) dfs(edges[start][i]); } // 求连通图的割顶。 void articulation_vertex(vector < int > &component, vector < string > &cameras) { int ncomponent = component.size(); for (int i = 0; i < ncomponent; i++) { nvertices = 0; memset(discovered, 0, sizeof(discovered)); discovered[component[i]] = true; dfs(i < (ncomponent - 1) ? component[i + 1] : component[i - 1]); if (nvertices < (ncomponent - 1)) cameras.push_back(locations[component[i]]); } } int main(int ac, char *av[]) { int cases = 1, ncities, routes; string location, start, end; while (cin >> ncities, ncities) { map < string, int > cityMap; for (int i = 1; i <= ncities; i++) { cin >> location; cityMap[location] = i; degree[i] = 0; locations[i] = location; } cin >> routes; for (int i = 1; i <= routes; i++) { cin >> start >> end; edges[cityMap[start]][degree[cityMap[start]]++] = cityMap[end]; edges[cityMap[end]][degree[cityMap[end]]++] = cityMap[start]; } // 找出所有连通子图,并求其割顶。 bool visited[MAXV + 1]; memset(visited, 0, sizeof(visited)); vector < string > cameras; for (int i = 1; i <= ncities; i++) if (visited[i] == false) { queue < int > vertices; vector < int > component; vertices.push(i); visited[i] = true; component.push_back(i); while (!vertices.empty()) { int v = vertices.front(); vertices.pop(); for (int i = 0; i < degree[v]; i++) if (visited[edges[v][i]] == false) { vertices.push(edges[v][i]); visited[edges[v][i]] = true; component.push_back(edges[v][i]); } } // 求连通子图的割顶。 articulation_vertex(component, cameras); } // 输出。 if (cases > 1) cout << endl; sort(cameras.begin(), cameras.end()); cout << "City map #" << cases++ << ": "; cout << cameras.size() << " camera(s) found" << endl; for (int i = 0; i < cameras.size(); i++) cout << cameras[i] << endl; } return 0; }