/* *State: POJ1236 164K 32MS C++ 2735B *题目大意: * 给定一个n (n<=100)个点的有向图,问: * Q1、最少需要选择多少个点,使得从这些点出发能遍历完整个图; * Q2、最少需要添加多少条有向边,使得整个图成为连通图; *解题思路: * 用tarjan_scc缩点之后求入度为0的节点个数即可Q1,之后再算加最少的 * 边使图构成强连通分量即可。算出度为0跟入度为0的数量的最大值。不管 * 缩点后的图是否有连通分支。 *注意: * 求加最少边变成强连通,只需算出度为0跟入度为0的数量的最大值即可。 * 无论改图是否有连通分量,都一样,但要注意排除该图本身就是强连通图 * 的可能性 */
View Code
State: 160K 0MS C++ 2158B #include <iostream> #include <vector> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 105; vector<int> vec[MAXN]; int dfn[MAXN], low[MAXN], inS[MAXN]; int step, scc, id[MAXN], myS[MAXN], top; //缩点建有向无环图 vector<int> sccvec[MAXN]; int vst[MAXN]; void addEdge(int u, int v) { vec[u].push_back(v); } void init() { top = 0; scc = 1; step = 0; for(int i = 0; i < MAXN; i++) { vst[i] = 0; sccvec[i].clear(); id[i] = -1; inS[i] = 0; dfn[i] = low[i] = -1; vec[i].clear(); } } void tarjan_scc(int n) { dfn[n] = low[n] = ++step; myS[top++] = n; inS[n] = 1; for(unsigned i = 0; i < vec[n].size(); i++) { int son = vec[n][i]; if(dfn[son] == -1) { tarjan_scc(son); low[n] = min(low[n], low[son]); } else if(inS[son] == 1) low[n] = min(low[n], dfn[son]); } if(dfn[n] == low[n]) { int tmp; do { tmp = myS[--top]; id[tmp] = scc; inS[tmp] = 0; }while(top != 0 && tmp != n); scc++; } } void deal_scc(int n, int &sol1, int &sol2) { int in[MAXN] = {0}, out[MAXN] = {0}; int inTree[MAXN] = {0}; for(int i = 1; i <= n; i++) { for(unsigned j = 0; j < vec[i].size(); j++) { int u = i, v = vec[i][j]; if(id[u] == id[v]) continue; else { sccvec[id[u]].push_back(id[v]); inTree[id[v]]++; in[id[v]]++; out[id[u]]++; } } } sol1 = 0; for(int i = 1; i < scc; i++) { if(inTree[i] == 0) sol1++; } //sol2 int IN = 0, OUT = 0, other = 0; for(int i = 1; i < scc; i++) { if(in[i] == 0) IN++; if(out[i] == 0) OUT++; } if(scc <= 2) sol2 = 0; else sol2 = max(IN, OUT); } int main(void) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int n; while(scanf("%d", &n) == 1) { init(); int u, v; for(int i = 1; i <= n; i++) { while(scanf("%d", &v), v) { addEdge(i, v); } } for(int i = 1; i <= n; i++) { if(dfn[i] == -1) tarjan_scc(i); } int sol1, sol2; deal_scc(n, sol1, sol2); printf("%d\n%d\n", sol1, sol2); } return 0; }