• Codeforces 505D


    D - Mr. Kitayuta's Technology

    题意:给n个点,然后给出m个条件a、b,表示a可到达b,求最少需要建多少条有向边才能满足所有条件

    思路:按所给的条件建有向图,可以发现,每一个联通块都是一个弱联通图,若一个m个点的联通块,如果没有环的话最少需要m-1条有向边,即连成一条链,若存在环,只需要m条边就可以连成一个强联通图,自然会满足联通块的所有条件,那么用拓扑判断有向环即可,注意建图的时候还是要建无向图,但是入度只记录条件给的边,因为如果建无向图,那么在dfs的时候不一定可以一次找到弱联通块所有的点,比如 1 2, 2 1这样的数据,所以建双向边,在每次dfs的时候把入度为0的点加入拓扑队列即可

    AC代码:

    #include "iostream"
    #include "string.h"
    #include "stack"
    #include "queue"
    #include "string"
    #include "vector"
    #include "set"
    #include "map"
    #include "algorithm"
    #include "stdio.h"
    #include "math.h"
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define ll long long
    #define endl ("
    ")
    #define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
    #define mem(a,x) memset(a,x,sizeof(a))
    #define mp(x,y) make_pair(x,y)
    #define pb(x) push_back(x)
    #define ft first
    #define sd second
    #define lrt (rt<<1)
    #define rrt (rt<<1|1)
    using namespace std;
    const long long INF = 1e18+1LL;
    const int inf = 1e9+1e8;
    const int N=1e5+100;
    const ll mod=1e9+7;
    
    int in[N],head[N],to[N<<1],nex[N<<1],tot=1;
    int n,m,ans,vis[N],mk[N];
    queue<int> Q;
    void add(int u, int v){
        to[tot]=v;
        nex[tot]=head[u];
        head[u]=tot++;
    }
    int dfs(int u){
        int ret=1; vis[u]=1;
        if(in[u]==0){
            Q.push(u);
            mk[u]=1;
        }
        for(int i=head[u]; i!=-1; i=nex[i]){
            int v=to[i];
            if(!vis[v]) ret+=dfs(v);
        }
        return ret;
    }
    bool topo(int u, int c){
        int k=0;
        while(!Q.empty()){
            int now=Q.front(); Q.pop(), k++;
            for(int i=head[now]; i!=-1; i=nex[i]){
                int v=to[i]; in[v]--;
                if(!mk[v] && in[v]==0){
                    Q.push(v);
                    mk[v]=1;
                }
            }
        }
        return k==c;
    }
    int main(){
        ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
        mem(head,-1);
        cin>>n>>m;
        for(int _=1; _<=m; ++_){
            int u, v; cin>>u>>v;
            add(u,v); add(v,u); in[v]++;
        }
        for(int i=1; i<=n; ++i){
            if(!vis[i] && in[i]==0){
                while(!Q.empty()) Q.pop();
                int c=dfs(i);
                if(topo(i,c)) ans+=c-1;
                else ans+=c;
            }
        }
        for(int i=1; i<=n; ++i){
            if(!vis[i]) ans++;
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    Linux系统运维之MYSQL数据库集群部署(主从复制)
    Linux系统运维之负载均衡Tengine
    Linux系统运维之subversionEdge部署
    Linux系统运维之Hadoop、Hive、Flume数据处理
    CoIDE在STM32系列单片机中的使用实践
    软硬件调试九法:第三条规则 不要想而要看
    《产品经理》读书笔记
    <读书笔记> 代码整洁之道
    关于鼠标手的症状和恢复方法
    <读书笔记>软件调试之道 :从大局看调试-理想的调试环境
  • 原文地址:https://www.cnblogs.com/max88888888/p/7342205.html
Copyright © 2020-2023  润新知