题目链接
输入一个由 n n n个顶点和 m m m条边组成的无向图,找一个长度 ≥ n \ge \sqrt n ≥n的环或者是顶点数为 n \sqrt n n的独立集(独立集中任意两个点没有直接边)。
此题用 D F S DFS DFS树求解,所谓 D F S DFS DFS树就是将图进行 D F S DFS DFS遍历之后导出的树,如下图所示。(粗线为树边,浅线为非树边)
D F S DFS DFS树有一个重要的性质,不在同一颗子树上的两点之间没有边(非树边只有可能是在同一条树链上),这个用反证法的思路和 D F S DFS DFS的性质能够容易看出。
D F S DFS DFS树找出的环不一定是最大环也不一定是最小环。比如下面这组数据。(找最小环需要用 F l o y d Floyd Floyd)
这道题也是DFS树留个坑。
#include
using namespace std;
const int maxn = 2e5 + 100;
typedef long long ll;
int n, m, d, flag, dep[maxn];
vector<int> G[maxn];
stack<int> s;
void dfs(int cur, int par){
dep[cur] = dep[par] + 1;
s.push(cur);
for(auto temp:G[cur]){
if(temp == par) continue;
if(!dep[temp]){
dfs(temp, cur);
if(flag) return;
s.pop();
}else{
if(dep[cur] - dep[temp] >= d - 1){ //找到符合条件的环
cout<<2<<'\n';
flag = 1;
cout<<dep[cur] - dep[temp] + 1<<'\n'<<s.top();
s.pop();
while(!s.empty()){
cout<<' '<<s.top();
if(s.top() == temp) return;
s.pop();
}
}
}
}
}
void solve(){
int cnt[maxn];
memset(cnt, 0, sizeof(cnt));
d = sqrt(n + 0.5);
if(n > d * d) ++d;
dfs(1, 0);
if(!flag){ //存在独立集
cout<<1<<'\n';
int maxi = 0, p, c = 0;
for(int i=1;i<=n;++i){
cnt[dep[i]%(d-1)]++;
if(cnt[dep[i]%(d-1)] > maxi){
maxi = cnt[dep[i]%(d-1)];
p = dep[i]%(d-1);
}
}
for(int i=1;i<=n;++i){
if(dep[i] % (d - 1) == p){
if(c) cout<<' ';
cout<<i;
++c;
if(c >= d) break;
}
}
}
}
int main(){
int t, i, j, u, v;
ios::sync_with_stdio(false);
cin>>n>>m;
for(i=1;i<=m;++i){
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
solve();
return 0;
}