abc142_f

abc142_f

题意简述:

给定一个 \(n\) 个点,\(m\) 条边的有向图 \((n \le 1000, m \le 2000)\)

找到一个子图,使得子图里每个点的入度和出度都等于 \(1\)

即找到一个环,环内的点都只向外连一条边

输出方案

正解 :

手玩发现可以先找到任意一个环

假如环内有连边,就把环缩小,一直缩到环内每个点出度都为 \(1\)

模拟缩环的过程,发现只要找到一个环内的最小环即可

那么就用 bfs 搜出一颗有向树,第一条返祖边所连的两个点所在的那个最小环即为答案

找方案的话可以记一下路径上的 pre (前驱)

现场用 dfs 也过了,不过被 dqk hack 掉了

Code:

/*
    bfs 找环
*/
#include <bits/stdc++.h>
#define N 1005
#define M 2005

using namespace std;

int n, m;
int dep[N];
int head[N], nex[M], to[M], e;
int stk[N], top;
bool instack[N], vis[N], G[N][N];
vector<int> res;

inline int Rd() {
    int x = 0; char ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    return x;
}
inline void Ae(int u, int v) {
    nex[++e] = head[u], head[u] = e;
    to[e] = v;
}

void calc(int u, int v) {
    do {
        res.push_back(stk[top]);
    } while(stk[top--] != v);
    int ans = res.size();
    printf("%d\n", ans);
    for(int i = 0; i < ans; ++i) printf("%d\n", res[i]);
    exit(0);
}
void dfs(int u) {
    stk[++top] = u;
    instack[u] = vis[u] = true;
    for(int i = head[u]; i; i = nex[i]) {
        int v = to[i];
        if(vis[v]) {
            if(instack[v]) calc(u, v);
        } else {
            dfs(v);
        }
    }
    instack[u] = false, --top;
    return;
}

int main() {
    n = Rd(), m = Rd();
    for(int i = 1; i <= m; ++i) {
        int u = Rd(), v = Rd();
        G[u][v] = true;
        Ae(u, v);
    }
    
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= n; ++j) {
            if(G[i][j] && G[j][i]) {
                puts("2");
                printf("%d\n%d\n", i, j);
                return 0;
            }   
        }
    }
    for(int i = 1; i <= n; ++i)
        if(!vis[i])
            dfs(i);
    puts("-1");
    return 0;   
}

猜你喜欢

转载自www.cnblogs.com/Lskkkno1/p/11605102.html
142