$\newcommand{\O}{\mathrm{O}}$
なもりグラフとは $n$ 頂点 $n$ 辺の連結な無向グラフのことでグラフはサイクル+サイクルから生える木の構造になる. 名称の由来は このアカウント のアイコンだそうです.
以下の実装はサイクル上の頂点を loop に, サイクルから生える木を graph に格納する(分解する)ような実装になっている.
時間計算量: $\O (n)$
class Namori{ public: int V; vector<vector<int> > G, graph; vector<int> deg, loop; vector<bool> flag; Namori(int node_size) : V(node_size), G(V), deg(V, 0), flag(V, false){} void add_edge(int u,int v){ G[u].push_back(v), G[v].push_back(u); deg[u]++, deg[v]++; } void dfs(int u){ loop.push_back(u); for(int v : G[u]){ if(flag[v]) continue; flag[v] = true; dfs(v); } } void build(){ graph.resize(V); queue<int> que; // 葉の頂点を que に突っ込む for(int i = 0; i < V; i++){ if(deg[i] == 1){ que.push(i); flag[i] = true; } } // 葉からサイクル上の頂点に向かって登っていく while(!que.empty()){ int p = que.front(); que.pop(); for(int v : G[p]){ if(flag[v]) continue; deg[v]--; //サイクルから端 graph[v].push_back(p); //端からサイクル graph[p].push_back(v); if(deg[v] > 1) continue; que.push(v); flag[v] = true; } } // サイクル上の頂点を loop に格納 for(int i = 0; i < V; i++){ if(flag[i]) continue; flag[i] = true; dfs(i); break; } } };
Atcoder : Namori Grundy 提出コード