hdu 3639 Hawk-and-Chicken 强连通分支
刚看了强连通分量,找来些题练练。发现强连通不会赤裸裸地考,会结合一些其它知识。
这题做得比较曲折,一开始没有强连通,对反向图的每个点进行一次dfs, 发现超时,后来用了强连通,弄了很久才弄出。
解题思路:先把强连通分支压缩成一个点,再组成一个有向无环反向图, 对每个入度为0的点进行dfs, 找出最大的值即可。注意到,答案只能是在反向图入度为0 的点中。
#include <iostream> #include <vector> using namespace std; const int MAX = 5005; bool isvisit[MAX]; vector<int> GT[MAX]; vector<int> G[MAX]; vector<int> arcs[MAX]; int n, m; int scc_v[MAX]; int cnt, total, scc, time; int f[MAX]; int id[MAX]; int ingree[MAX]; int ans[MAX]; void dfs(int v) { isvisit[v] = true; for (int i = 0; i < G[v].size(); i++) if (!isvisit[G[v][i]]) dfs(G[v][i]); f[cnt++] = v; } void dfs2(int v) { id[v] = scc; isvisit[v] = true; time++; for (int i = 0; i < GT[v].size(); i++) if ( !isvisit[GT[v][i]]) dfs2(GT[v][i]); } void SCC() { memset(isvisit, false, sizeof(isvisit)); cnt = 0; for (int i = 0; i < n; i++) if (!isvisit[i]) dfs(i); memset(isvisit, false, sizeof(isvisit)); scc = 0; for (int i = cnt-1; i >= 0; i--) { if (!isvisit[f[i]]) { time = 0; dfs2(f[i]); scc_v[scc++] = time; //记录每一个强连通分支的顶点个数 } } } void dfs3(int v) { isvisit[v] = true; total += scc_v[v]; for (int i = 0; i < arcs[v].size(); i++) if (!isvisit[arcs[v][i]]) dfs3(arcs[v][i]); } int main() { int cases; int a, b; cin >> cases; for (int k = 0; k < cases; k++) { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { G[i].clear(); GT[i].clear(); arcs[i].clear(); } for (int i = 0; i < m; i++) { scanf("%d%d", &a, &b); G[a].push_back(b); GT[b].push_back(a); } SCC(); //求强连通分量 memset(ingree, 0, sizeof(ingree)); //创建新的强连通分量的反向图 for (int i = 0; i < n; i++) for (int j = 0; j < G[i].size(); j++) if (id[i] != id[G[i][j]]) { arcs[id[G[i][j]]].push_back(id[i]); ingree[id[i]]++; } int maximum = -1; maximum = -1; memset(ans, -1, sizeof(ans)); //搜索入度为0的顶点 for (int i = 0; i < scc; i++) if (ingree[i] == 0) { total = 0; memset(isvisit, false, sizeof(isvisit)); dfs3(i); ans[i] = total; maximum = max(maximum, ans[i]); } int i; cout << "Case " << k+1 << ": " << maximum - 1<< endl; for (i = 0; i < n; i++) if ( ans[id[i]] == maximum) { printf("%d", i); break; } for (i++; i < n; i++) if ( ans[id[i]] == maximum) printf(" %d", i); printf("\n"); } return 0; }