/* *State: POJ3177 Accepted 340K 16MS C++ 1877B *题目大意: * 给出一个无向连通图,判断最少需要加多少条边,才能使得 * 任意两点之间至少有两条相互"边独立"的道路.注意,可能 * 含有重边. *解题思路: * 先缩点,之后形成一棵树,然后求(叶子节点数量+1)/ 2即可。 */
View Code
#include <iostream> #include <vector> #include <stack> using namespace std; const int MAXN = 5005; const int MAXE = 10005; vector<int> vec[MAXN]; stack<int> S; int dfn[MAXN], low[MAXN], step; int id[MAXN], scc; void init() { while(!S.empty()) S.pop(); step = 0; scc = 1; for(int i = 0; i < MAXN; i++) { id[i] = -1; vec[i].clear(); dfn[i] = low[i] = -1; } } void addEdge(int u, int v) { vec[u].push_back(v); vec[v].push_back(u); } void tarjan_scc(int n, int father) { dfn[n] = low[n] = ++step; S.push(n); int flag = 0; for(unsigned i = 0; i < vec[n].size(); i++) { int son = vec[n][i]; if(son == father && !flag) { flag = 1; continue; } if(dfn[son] == -1) { tarjan_scc(son, n); low[n] = min(low[n], low[son]); } else low[n] = min(low[n], dfn[son]); } if(low[n] == dfn[n]) { int tmp; do { tmp = S.top(); id[tmp] = scc; // cout << tmp << " "; S.pop(); }while(!S.empty() && tmp != n); scc++; //cout << endl << "---------------" << endl; } } void deal_scc(int n, int &sol) { int u, v; int du[MAXN] = {0}; for(int i = 1; i <= n; i++) { for(unsigned j = 0; j < vec[i].size(); j++) { u = i, v = vec[i][j]; if(id[u] == id[v]) continue; else { du[id[v]]++; du[id[u]]++; } } } int sum = 0; for(int i = 1; i < scc; i++) { if(du[i] == 2) sum++; } sum++; sol = sum / 2; } int main(void) { #ifndef ONLINE_JUDGE //freopen("in.txt", "r", stdin); #endif int n, m; while(scanf("%d %d", &n, &m) == 2) { init(); int u, v; for(int i = 0; i < m; i++) { scanf("%d %d", &u, &v); addEdge(u, v); } tarjan_scc(1, 1); int sol; deal_scc(n, sol); printf("%d\n", sol); //cout << "****************" << endl; } return 0; }
//POJ3352 //State: POJ3352 Accepted 280K 47MS C++ 1865B //题意与上述的题一模一样
View Code
#include <iostream> #include <vector> #include <stack> using namespace std; const int MAXN = 1005; vector<int> vec[MAXN]; stack<int> S; int dfn[MAXN], low[MAXN], step; int id[MAXN], scc; void init() { while(!S.empty()) S.pop(); step = 0; scc = 1; for(int i = 0; i < MAXN; i++) { id[i] = -1; vec[i].clear(); dfn[i] = low[i] = -1; } } void addEdge(int u, int v) { vec[u].push_back(v); vec[v].push_back(u); } void tarjan_scc(int n, int father) { dfn[n] = low[n] = ++step; S.push(n); int flag = 0; for(unsigned i = 0; i < vec[n].size(); i++) { int son = vec[n][i]; if(son == father && !flag) { flag = 1; continue; } if(dfn[son] == -1) { tarjan_scc(son, n); low[n] = min(low[n], low[son]); } else low[n] = min(low[n], dfn[son]); } if(low[n] == dfn[n]) { int tmp; do { tmp = S.top(); id[tmp] = scc; // cout << tmp << " "; S.pop(); }while(!S.empty() && tmp != n); scc++; //cout << endl << "---------------" << endl; } } void deal_scc(int n, int &sol) { int u, v; int du[MAXN] = {0}; for(int i = 1; i <= n; i++) { for(unsigned j = 0; j < vec[i].size(); j++) { u = i, v = vec[i][j]; if(id[u] == id[v]) continue; else { du[id[v]]++; du[id[u]]++; } } } int sum = 0; for(int i = 1; i < scc; i++) { if(du[i] == 2) sum++; } sum++; sol = sum / 2; } int main(void) { #ifndef ONLINE_JUDGE freopen("in3352.txt", "r", stdin); #endif int n, m; while(scanf("%d %d", &n, &m) == 2) { init(); int u, v; for(int i = 0; i < m; i++) { scanf("%d %d", &u, &v); addEdge(u, v); } tarjan_scc(1, 1); int sol; deal_scc(n, sol); printf("%d\n", sol); //cout << "****************" << endl; } return 0; }