DFS Codeforces505D Mr. Kitayuta's Technology

传送门:点击打开链接

题意:告诉你n个点,和m条关系,每个关系有u和v,要求u能通过有向边到达v,问要完成这个有向图至少需要多少条边。

思路:就是个xjb的贪心....首先,我们把边按无向图处理,把图分成很多个分块。

对于每个分块,如果这个分块里存在环,那么说明边数>=节点数

对于一个分块,假如我把这些点首尾相连,此时是完美的!因为现在我用了最少的边数,使得可以从一个点到任意一个点,那么无论你给的关系有多么复杂,只要是一个连通图里面的,都是可以做到的。

所以我们就能找出xjb贪心了:

对于一个连通块,如果里面有有向环,那么答案等于点数

如果不存在有向环,答案等于点数-1

然后再xjb搞就行了

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int>PII;

const int MX = 2e5 + 5;
const int INF = 0x3f3f3f3f;

struct Edge {
    int v, nxt, sign;
} E[MX];
int Head[MX], rear;
void edge_init() {
    rear = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int s) {
    E[rear].v = v;
    E[rear].nxt = Head[u];
    E[rear].sign = s;
    Head[u] = rear++;
}

int n, m;
int A[MX], cnt[MX], cir[MX], vis[MX], siz;
int DFS1(int u, int id) {
    A[u] = -1;
    int ret = 1;
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(!A[v]) ret += DFS1(v, id);
    }
    A[u] = id;
    return ret;
}
bool DFS2(int u) {
    vis[u] = -1;
    bool ret = false;
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(E[i].sign) {
            if(vis[v] == -1) {
                ret = true; break;
            }
            if(!vis[v] && DFS2(v)) {
                ret = true; break;
            }
        }
    }
    vis[u] = 1;
    return ret;
}
int solve() {
    siz = 0;
    memset(A, 0, sizeof(A));
    memset(cir, 0, sizeof(cir));
    memset(cnt, 0, sizeof(cnt));
    memset(vis, 0, sizeof(vis));

    for(int i = 1; i <= n; i++) {
        if(!A[i]) siz++, cnt[siz] = DFS1(i, siz);
        if(!vis[i] && DFS2(i)) cir[A[i]] = 1;
    }

    int ans = 0;
    for(int i = 1; i <= siz; i++) {
        if(cir[i]) ans += cnt[i];
        else ans += cnt[i] - 1;
    }
    return ans;
}

int main() {
    edge_init(); //FIN;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        edge_add(u, v, 1);
        edge_add(v, u, 0);
    }
    printf("%d\n", solve());
    return 0;
}


你可能感兴趣的:(DFS Codeforces505D Mr. Kitayuta's Technology)