(未更新完,做到相关题再更新相关部分
无向图判断有无环并输出环上点 例题:H. Mad City
利用变种拓扑排序,先把度为1的点存入队中,每次取出队头,遍历邻接点,再将该条边删除也就是将邻接点度数减一,直至队空,然后所有度数不为0的点都是在环上的点,输出即可
code
for (int i = 0 ; i < n; i ++ ){ int x, y; cin >> x >> y; add (x, y), add (y, x); ind[x] ++, ind[y] ++ ; } function<void ()> topsort = [&]() { queue<int > q; for (int i = 1 ; i <= n; i ++ ) if (ind[i] == 1 ) q.push (i); while (q.size ()) { int u = q.front (); q.pop (); for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (-- ind[v] == 1 ) q.push (v); } } }; topsort ();for (int i = 1 ; i <= n; i ++ ) if (ind[i] > 1 ) ans = true ;
有向图判断有无环并输出环上点 拓扑排序 是目前来看的一种最优方式,即把所有入度为 0 的点存进队列,每次取出队头,遍历其邻接点,并将邻接点的入度减 1,若入度在减 1 后变为 0,则存入队列。以此类推,直到队列中没有元素,此时入度不为 0 的点在环上
code
for (int i = 0 ; i < n; i ++ ){ int x, y; cin >> x >> y; add (x, y); ind[y] ++ ; } function<void ()> topsort = [&]() { queue<int > q; for (int i = 1 ; i <= n; i ++ ) if (ind[i] == 0 ) q.push (i); while (q.size ()) { int u = q.front (); q.pop (); for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (-- ind[v] == 0 ) q.push (v); } } }; topsort ();for (int i = 1 ; i <= n; i ++ ) if (ind[i] > 0 ) ans = true ;
有向图找最小/大环 利用并查集,每加一条边,判断当前这两个端点是否连通,如果不连通就更新他们的长度和父结点情况,如果这两个端点已经连通,那么加上这一条边一定能使得形成一个环,环的长度就是两个端点距离祖先结点的和再加一
code
int find (int x) { if (x != fa[x]) { int last = fa[x]; fa[x] = find (fa[x]); dist[x] += dist[last]; } return fa[x]; } void func (int a, int b) { int aa = find (a), bb = find (b); if (aa == bb) ans = min (ans, dist[a] + dist[b] + 1 ); else { fa[a] = bb; dist[a] = dist[b] + 1 ; } } ans = 0x3f3f3f3f ; for (int i = 1 ; i <= n; i ++ ){ int x; cin >> x; func (i, x); }
有向图找到所有环 也就是找到有向图的强连通分量,利用tarjan算法
code
void tarjan (int u) { dfn[u] = low[u] = ++ timestamp; stk.push (u), in_stk[u] = true ; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (!dfn[j]) { tarjan (j); low[u] = min (low[u], low[j]); } else if (in_stk[j]) low[u] = min (low[u], dfn[j]); } if (dfn[u] == low[u]) { ++ scc_cnt; int y; do { y = stk.top (); stk.pop (); in_stk[y] = false ; id[y] = scc_cnt; } while (y != u); } }
缩点code
for (int i = 1 ; i <= n; i ++ ) for (int j = h[i]; ~j; j = ne[j]) { int k = e[j]; int a = id[i], b = id[k]; if (a != b) dout[a] ++ ; }