这道题是看了大神的解释才明白原来是求强连通分量(SCC, strongly connected components):https://www.byvoid.com/blog/usaco-533-schlnet。
GeeksforGeeks上面有求SCC的两种方法,讲得很详细:
http://www.geeksforgeeks.org/strongly-connected-components/
http://www.geeksforgeeks.org/tarjan-algorithm-find-strongly-connected-components/
包括跑两遍DFS中间加一个reverse的比较好理解的,也包括Tarjan的一遍DFS的。这里用的是后者。大神那里是前者。跑一遍DFS做法从时间上看比大神的跑两遍DFS的方法还慢,我估计主要原因是大神用的是array,我这里用的是vector。不过也不是很确定是不是这个原因。但是两遍DFS确实要好想些。
Executing... Test 1: TEST OK [0.003 secs, 3508 KB] Test 2: TEST OK [0.005 secs, 3508 KB] Test 3: TEST OK [0.003 secs, 3508 KB] Test 4: TEST OK [0.005 secs, 3508 KB] Test 5: TEST OK [0.008 secs, 3508 KB] Test 6: TEST OK [0.011 secs, 3508 KB] Test 7: TEST OK [0.008 secs, 3508 KB] Test 8: TEST OK [0.005 secs, 3508 KB] Test 9: TEST OK [0.014 secs, 3508 KB] Test 10: TEST OK [0.005 secs, 3508 KB] Test 11: TEST OK [0.008 secs, 3508 KB] All tests OK.
/* ID: thestor1 LANG: C++ TASK: schlnet */ #include <iostream> #include <fstream> #include <cmath> #include <cstdio> #include <cstring> #include <climits> #include <cassert> #include <string> #include <vector> #include <set> #include <map> #include <queue> #include <stack> #include <algorithm> #include <cassert> using namespace std; // A recursive function that finds and prints strongly connected // components using DFS traversal // u --> The vertex to be visited next void SCC(int u, vector<vector<int> > &sccs, vector<int> &dist, vector<int> &low, stack<int> &st, vector<int> &inStack, int ×tamp, const vector<vector<int> > &adjs) { // Initialize discovery time and low value dist[u] = low[u] = timestamp; timestamp++; st.push(u); inStack[u] = true; for (int i = 0; i < adjs[u].size(); ++i) { int v = adjs[u][i]; // If v is not visited yet, then recur for it if (dist[v] < 0) { SCC(v, sccs, dist, low, st, inStack, timestamp, adjs); low[u] = min(low[u], low[v]); } else if (inStack[v]) { //// Update low value of 'u' only of 'v' is still in stack // (i.e. it's a back edge, not cross edge). low[u] = min(low[u], low[v]); } } // head node found, pop the stack and generate an SCC if (dist[u] == low[u]) { int v; std::vector<int> scc; while (st.top() != u) { v = st.top(); // assert(low[v] == low[u]); scc.push_back(v); st.pop(); inStack[v] = false; } v = st.top(); assert(v == u); scc.push_back(v); st.pop(); inStack[v] = false; sccs.push_back(scc); } } int main() { ifstream fin("schlnet.in"); ofstream fout("schlnet.out"); int N; fin>>N; vector<vector<int> > adjs(N, vector<int>()); for (int i = 0; i < N; ++i) { int v; fin>>v; while (v != 0) { adjs[i].push_back(v - 1); fin>>v; } } fin.close(); // for (int i = 0; i < N; ++i) // { // cout<<i<<":"; // for (int j = 0; j < adjs[i].size(); ++j) // { // cout<<adjs[i][j]<<"\t"; // } // cout<<endl; // } vector<vector<int> > sccs; vector<int> dist(N, -1); vector<int> low(N, -1); stack<int> st; vector<int> inStack(N, false); int timestamp = 0; for (int u = 0; u < N; ++u) { if (dist[u] < 0) { SCC(u, sccs, dist, low, st, inStack, timestamp, adjs); } } // cout<<"sccs:"<<endl; // for (int i = 0; i < sccs.size(); ++i) // { // for (int j = 0; j < sccs[i].size(); ++j) // { // cout<<sccs[i][j]<<", low: "<<low[sccs[i][j]]<<", dist: "<<dist[sccs[i][j]]<<endl; // } // } if (sccs.size() == 1) { fout<<1<<endl; fout<<0<<endl; } else { std::vector<int> sccid(N, 0); for (int i = 0; i < sccs.size(); ++i) { for (int j = 0; j < sccs[i].size(); ++j) { sccid[sccs[i][j]] = i; } } // cout << "sccid:" << endl; // for (int i = 0; i < sccid.size(); ++i) // { // cout << i << "," << sccid[i]<<endl; // } // std::vector<std::vector<int> > dense(sccs.size(), std::vector<int>()); std::vector<int> in(sccs.size(), 0); std::vector<int> out(sccs.size(), 0); for (int u = 0; u < adjs.size(); ++u) { for (int i = 0; i < adjs[u].size(); ++i) { // sccid[u], sccid[adjs[u][i]] // dense[sccid[u]].push_back(sccid[adjs[u][i]]); // dense[sccid[adjs[u][i]]].push_back(sccid[u]); if (sccid[u] != sccid[adjs[u][i]]) { in[sccid[adjs[u][i]]]++; out[sccid[u]]++; } } } int incnt = 0, outcnt = 0; for (int i = 0; i < sccs.size(); ++i) { if (in[i] == 0) { incnt++; } if (out[i] == 0) { outcnt++; } } fout<<incnt<<endl; fout<<max(incnt, outcnt)<<endl; } fout.close(); return 0; }
assert(low[v] == low[u]);这句有时是无法成立的。不知道为啥。