1. 程式人生 > 實用技巧 >DFS找最小環

DFS找最小環

DFS找最小環

對於無向無權圖,可以直接使用dfs來找最小環,並找出環上的點

例題

http://codeforces.com/contest/1364/problem/D

題意

給出一張圖和一個引數k,可以選擇完成兩個任務中的一個

  • 找到一個獨立集恰好有$\lceil k/2 \rceil $個點
  • 找到一個簡單環,環長最多為k

題解

對於樹形結構,直接判斷一下完成任務1即可

對於非樹形結構,一定有環,找到最小環,如果最小環長度小於等於k,直接完成任務2,否則在環上隔一個取一個完成任務1即可

程式碼

在dfs中,滿足dep[u]-dep[v]>0即為找到一個環,使用pre記錄一下即可還原環上的點

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
struct READ {
    inline char read() {
    #ifdef Artoriax
        return getchar();
    #endif
        const int LEN = 1 << 18 | 1;
        static char buf[LEN], *s, *t;
        return (s == t) && (t = (s = buf) + fread(buf, 1, LEN, stdin)), s == t ? -1 : *s++;
    }
    inline READ & operator >> (char *s) {
        char ch;
        while (isspace(ch = read()) && ~ch);
        while (!isspace(ch) && ~ch) *s++ = ch, ch = read(); *s = '\0';
        return *this;
    }
    inline READ & operator >> (string &s) {
        s = ""; char ch;
        while (isspace(ch = read()) && ~ch);
        while (!isspace(ch) && ~ch) s += ch, ch = read();
        return *this;
    }
    template <typename _Tp> inline READ & operator >> (_Tp&x) {
        char ch, flag;
        for(ch = read(),flag = 0; !isdigit(ch) && ~ch; ch = read()) flag |= ch == '-';
        for(x = 0; isdigit(ch); ch = read()) x = x * 10 + (ch ^ '0');
        flag && (x = -x);
        return *this;
    }
} in;

const int N = 2e5 + 50;
vector<int> G[N];
int pos;
int dep[N];
int pre[N];
int mn = 1e9;
void dfs(int u, int fa, int d) {
    pre[u] = fa;
    dep[u] = d;
    for (int v : G[u]) {
        if (v == fa) continue;
        if (!dep[v]) dfs(v, u, d + 1);
        else if (dep[u] - dep[v] > 0 && dep[u] - dep[v] + 1 < mn){
            mn = dep[u] - dep[v] + 1;
            pos = u;
        }
    }
}
int main() {
    int n, m, k; in >> n >> m >> k;
    for (int i = 1; i <= m; i++) {
        int u, v; in >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, 0, 1);
    if (m == n - 1) {
        vector<int> res[2];
        for (int i = 1; i <= n; i++) {
            res[dep[i] & 1].push_back(i);
        }
        puts("1");
        int sz = (k + 1) / 2;
        if (res[0].size() < res[1].size()) {
            for (int i = 0; i < sz; i++) printf("%d ", res[1][i]);
        }
        else {
            for (int i = 0; i < sz; i++) printf("%d ", res[0][i]);
        }
        return 0;
    }
    if (mn <= k) {
        puts("2");
        printf("%d\n", mn);
        while (mn--) {
            printf("%d ", pos);
            pos = pre[pos];
        }
    }
    else {
        puts("1");
        for (int i = 0; i < (k + 1) / 2; i++) {
            printf("%d ", pos);
            pos = pre[pre[pos]];
        }
    }
    return 0;
}