Light OJ 1034 - Hit the Light Switches(强联通分量)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1034
题目大意:有n盏灯,有m个关系, 关系a,b表示如果a灯开关打开那么b灯也会亮起来, 现在求至少需要打开多少开关使所有灯都亮。
题目思路:先由强联通分量缩点, 得到DAG图, 然后根据DAG图,求出有多少入度为0的点, 即为所求。
代码如下:
#include<bits/stdc++.h> using namespace std; const int N = 10007; vector<int>vec[N], stk; int low[N], dfn[N], belong[N], in[N]; bool mk[N]; int tot, cou_scc; void tarjan(int u, int f) { dfn[u] = low[u]= tot ++; stk.push_back(u), mk[u] = true; for(int i=0; i<vec[u].size(); ++ i) { int v = vec[u][i]; if(dfn[v] == -1) { tarjan(v, u); low[u] = min(low[u], low[v]); } else if(mk[v]) { low[u] = min(low[u], dfn[v]); } } if(low[u] == dfn[u]) { ++ cou_scc; while(1) { int v = stk.back(); stk.pop_back(); mk[v] = false; belong[v] = cou_scc; if(u == v) break; } } } void solve(int cases) { int n, m; scanf("%d%d", &n, &m); for(int i=1; i<=n; ++ i) vec[i].clear(); int u, v; for(int i=1; i<=m; ++ i) { scanf("%d%d", &u, &v); vec[u].push_back(v); } memset(low, -1, sizeof(low)); memset(dfn, -1, sizeof(dfn)); memset(mk, false, sizeof(mk)); tot = 0, cou_scc = 0; for(int i=1; i<=n; ++ i) { if(dfn[i] == -1) tarjan(i, -1); } memset(in, 0, sizeof(in)); for(int i=1; i<=n; ++ i) { for(int j=0; j<vec[i].size(); ++ j) { int v = vec[i][j]; if(belong[i] != belong[v]) in[belong[v]] ++; } } int ans = 0; for(int i=1; i<=cou_scc; ++ i) { if(in[i] == 0) ans ++; } printf("Case %d: %d\n", cases, ans); } int main() { int t; scanf("%d", &t); for(int i=1; i<=t; ++ i) solve(i); return 0; }