試題編號: | 201509-4 |
試題名稱: | 高速公路 |
時間限制: | 1.0s |
內存限制: | 256.0MB |
問題描述: | 問題描述 某國有n個城市,為了使得城市間的交通更便利,該國國王打算在城市之間修一些高速公路,由于經費限制,國王打算第一階段先在部分城市之間修一些單向的高速公路。 現在,大臣們幫國王擬了一個修高速公路的計劃??戳擞媱澓?,國王發現,有些城市之間可以通過高速公路直接(不經過其他城市)或間接(經過一個或多個其他城市)到達,而有的卻不能。如果城市A可以通過高速公路到達城市B,而且城市B也可以通過高速公路到達城市A,則這兩個城市被稱為便利城市對。 國王想知道,在大臣們給他的計劃中,有多少個便利城市對。輸入格式 輸入的第一行包含兩個整數n, m,分別表示城市和單向高速公路的數量?! 〗酉聛韒行,每行兩個整數a, b,表示城市a有一條單向的高速公路連向城市b。輸出格式 輸出一行,包含一個整數,表示便利城市對的數量。樣例輸入5 51 22 33 44 23 5樣例輸出3樣例說明![]() |
問題鏈接:CCF201509試題。
問題描述:(參見上文)。
問題分析:這是一個強聯通圖的問題,用Tarjan算法來解決。另外一個算法是kosaraju算法,也用于解決強聯通圖問題。
程序說明:本程序采用Tarjan算法。主函數main()中,創建圖對象是參數本應該用n,但是提交后出現了運行錯誤,所有改成n+1。程序通過使用Tarjan算法類(參見以下鏈接)來實現,做了簡單修改,使用變量ans來存儲結果,其中增加了中間變量count。
求得強聯通子圖后,對于每一個強聯通子圖如果有k個結點,若k>1則強聯通對結點的數量為k*(k-1)/2,若k=1則為0。
相關鏈接:Tarjan算法查找強聯通組件。
提交后得100分的C++語言程序如下:
/* CCF201509-4 高速公路 */#include <iostream>#include <list>#include <stack>using namespace std;const int NIL = -1;int ans = 0;// A class that rePResents an directed graphclass Graph{ int V; // No. of vertices list<int> *adj; // A dynamic array of adjacency lists // A Recursive DFS based function used by SCC() void SCCUtil(int u, int disc[], int low[], stack<int> *st, bool stackMember[]);public: Graph(int V); // Constructor void addEdge(int v, int w); // function to add an edge to graph void SCC(); // prints strongly connected components};Graph::Graph(int V){ this->V = V; adj = new list<int>[V];}void Graph::addEdge(int v, int w){ adj[v].push_back(w);}// A recursive function that finds and prints strongly connected// components using DFS traversal// u --> The vertex to be visited next// disc[] --> Stores discovery times of visited vertices// low[] -- >> earliest visited vertex (the vertex with minimum// discovery time) that can be reached from subtree// rooted with current vertex// *st -- >> To store all the connected ancestors (could be part// of SCC)// stackMember[] --> bit/index array for faster check whether// a node is in stackvoid Graph::SCCUtil(int u, int disc[], int low[], stack<int> *st, bool stackMember[]){ // A static variable is used for simplicity, we can avoid use // of static variable by passing a pointer. static int time = 0; // Initialize discovery time and low value disc[u] = low[u] = ++time; st->push(u); stackMember[u] = true; // Go through all vertices adjacent to this list<int>::iterator i; for (i = adj[u].begin(); i != adj[u].end(); ++i) { int v = *i; // v is current adjacent of 'u' // If v is not visited yet, then recur for it if (disc[v] == -1) { SCCUtil(v, disc, low, st, stackMember); // Check if the subtree rooted with 'v' has a // connection to one of the ancestors of 'u' // Case 1 (per above discussion on Disc and Low value) low[u] = min(low[u], low[v]); } // Update low value of 'u' only of 'v' is still in stack // (i.e. it's a back edge, not cross edge). // Case 2 (per above discussion on Disc and Low value) else if (stackMember[v] == true) low[u] = min(low[u], disc[v]); } // head node found, pop the stack and print an SCC int w = 0; // To store stack extracted vertices int count = 0; if (low[u] == disc[u]) { while (st->top() != u) { w = (int) st->top();// cout << w << " "; count++; stackMember[w] = false; st->pop(); } w = (int) st->top();// cout << w << "/n"; count++; stackMember[w] = false; st->pop(); } if(count > 1) ans += count * (count -1) / 2;}// The function to do DFS traversal. It uses SCCUtil()void Graph::SCC(){ int *disc = new int[V]; int *low = new int[V]; bool *stackMember = new bool[V]; stack<int> *st = new stack<int>(); // Initialize disc and low, and stackMember arrays for (int i = 0; i < V; i++) { disc[i] = NIL; low[i] = NIL; stackMember[i] = false; } // Call the recursive helper function to find strongly // connected components in DFS tree with vertex 'i' for (int i = 0; i < V; i++) if (disc[i] == NIL) SCCUtil(i, disc, low, st, stackMember);}int main(){ int n, m, src, dest; cin >> n >> m; Graph g(n+1); for(int i=1; i<=m; i++) { cin >> src >> dest; g.addEdge(src, dest); } g.SCC(); cout << ans << endl; return 0;}
新聞熱點
疑難解答