标签:
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3836
Time Limit: 12000/4000 MS (Java/Others) Memory Limit: 104857/104857 K (Java/Others)
Total Submission(s): 3469 Accepted Submission(s): 1199
给你一个有向图,问你至少需要添加多少条边构成强联通。
先Tarjan缩点,然后统计有出度为0和入度为0的点的个数,取个最大值即可,至于为什么,请自行脑补。
#include<iostream> #include<vector> #include<cstring> #include<algorithm> #include<stack> #define MAX_N 20002 using namespace std; vector<int> G[MAX_N]; int dfn[MAX_N],low[MAX_N],ind=0; bool vis[MAX_N]; bool inStack[MAX_N]; stack<int> st; int color[MAX_N],tot=0; vector<int> newG[MAX_N]; vector<int> newrG[MAX_N]; void Tarjan(int u) { dfn[u] = low[u] = ++ind; vis[u] = 1; inStack[u] = 1; st.push(u); for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if (!vis[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if (inStack[v]) low[u] = min(dfn[v], low[u]); } if (dfn[u] == low[u]) { int x; do { x = st.top(); st.pop(); inStack[x] = 0; color[x] = tot; } while (x != u); tot++; } } int main() { int n, m; cin.sync_with_stdio(false); while (cin >> n >> m) { memset(vis, 0, sizeof(vis)); memset(inStack, 0, sizeof(inStack)); while (st.size())st.pop(); for (int i = 0; i <= n; i++)G[i].clear(); for (int i = 0; i <= n; i++)newG[i].clear(); for (int i = 0; i <= n; i++)newrG[i].clear(); ind = 0; tot = 0; memset(color, 0, sizeof(color)); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; G[u].push_back(v); } for (int i = 1; i <= n; i++) if (!vis[i])Tarjan(i); for (int i = 1; i <= n; i++) for (int j = 0; j < G[i].size(); j++) { int u = color[i], v = color[G[i][j]]; if (u == v)continue; newG[u].push_back(v); newrG[v].push_back(u); } if (tot == 1) { cout << 0 << endl; continue; } int a = 0, b = 0; for (int i = 0; i < tot; i++)if (newG[i].size() == 0)a++; for (int i = 0; i < tot; i++)if (newrG[i].size() == 0)b++; cout << max(a, b) << endl; } return 0; }
标签:
原文地址:http://www.cnblogs.com/HarryGuo2012/p/4715235.html