zoukankan      html  css  js  c++  java
  • 训练指南 UVALive


    layout: post
    title: 训练指南 UVALive - 4287 (强连通分量+缩点)
    author: "luowentaoaa"
    catalog: true
    mathjax: true
    tags:
    - 强连通分量
    - 图论
    - 训练指南


    Proving Equivalences

    UVALive - 4287

    题意

    有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导。

    题解

    由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图。找出所有的强连通分量,将每一个连通分量视作一个大节点,则整张图变成了一张DAG。设出度为0的大节点个数为a,入度为0的大节点个数为b,则答案就是max(a,b)。为什么是这样呢?因为要使等价证明前进下去,每个大节点的出度和入度都必须不能是0。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int maxn=1e6+50;
    const ll inf=0x3f3f3f3f3f3f3f3fLL;
    vector<int>G[maxn];
    int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
    stack<int>S;
    void dfs(int u){
        pre[u]=lowlink[u]=++dfs_clock;
        S.push(u);
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!pre[v]){
                dfs(v);
                lowlink[u]=min(lowlink[u],lowlink[v]);
            }
            else if(!sccno[v]){
                lowlink[u]=min(lowlink[u],pre[v]);
            }
        }
        if(lowlink[u]==pre[u]){
            scc_cnt++;
            for(;;){
                int x=S.top();S.pop();
                sccno[x]=scc_cnt;
                if(x==u)break;
            }
        }
    }
    void find_scc(int n){
        dfs_clock=scc_cnt=0;
        memset(sccno,0,sizeof(sccno));
        memset(pre,0,sizeof(pre));
        for(int i=0;i<n;i++)
            if(!pre[i])dfs(i);
    }
    int in[maxn],out[maxn];
    
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int t;
        cin>>t;
        while(t--){
            int n,m;
            cin>>n>>m;
            for(int i=0;i<=n;i++)G[i].clear();
            for(int i=0;i<m;i++){
                int u,v;
                cin>>u>>v;u--;v--;
                G[u].push_back(v);
            }
            find_scc(n);
            for(int i=1;i<=scc_cnt;i++)in[i]=out[i]=1;
            for(int u=0;u<n;u++)
            for(int i=0;i<G[u].size();i++){
                int v=G[u][i];
                if(sccno[u]!=sccno[v])in[sccno[v]]=out[sccno[u]]=0;
            }
            int a=0,b=0;
            for(int i=1;i<=scc_cnt;i++){
                if(in[i])a++;
                if(out[i])b++;
            }
            if(scc_cnt==1)cout<<0<<endl;
            else cout<<max(a,b)<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    获取最近一周
    git设置个人信息
    ajax的content-download时间过慢问题的解决与思考
    element UI table中字符太多
    git 合并代码冲突最终解决办法
    thinkphp swoole 的使用
    vue elemnet 二进制文件上传
    Python+Selenium+Chrome 笔记(2)Selenium的Hello World
    chrome 自动测试插件
    php-fpm 错误日志 与 php 错误日志的用法
  • 原文地址:https://www.cnblogs.com/luowentao/p/10342648.html
Copyright © 2011-2022 走看看