Light OJ 1034 - Hit the Light Switches(强联通分量)
Posted aiterator
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于Light OJ 1034 - Hit the Light Switches(强联通分量)的主要内容,如果未能解决你的问题,请参考以下文章
Light OJ 1025 - The Specials Menu(动态规划-区间dp)
Light oj 1099 - Not the Best 次短路
1341 - Aladdin and the Flying Carpet ---light oj (唯一分解定理+素数筛选)
Light oj 1251 - Forming the Council 2-sat推断是否存在可行解 + 反向拓扑输出可行解