zoukankan      html  css  js  c++  java
  • [BZOJ 2208] 连通数

    Link:

    BZOJ 2208 连通数

    Solution:

    传递闭包模板题

    传递闭包是集合中最小的二元关系,其实就是对二元关系的不断拓展,一般用$floyd$求解

    这里要先跑一遍$tarjan$求出$SCC$,然后在$TopoSort$时顺便传递闭包,最后统计答案即可

    Tips:

    1、在$DAG$上递推使用拓扑排序更高效,直接$dfs$时间复杂度没有保证,很可能$TLE$

    2、如需对二进制位统一处理(位运算),使用$bitset$,能通过压位快32倍

    3、这题$O(n*m)$和$O(frac{n^3}{32})$的纯暴力都能过……

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=2005;
    ll res=0;
    bool vis[MAXN],instack[MAXN];
    vector<int> G[MAXN];char dat[MAXN][MAXN];
    int n,in[MAXN],low[MAXN],dfn[MAXN],col[MAXN],sum[MAXN],tp=0,cnt=0;
    
    stack<int> s;
    bitset<MAXN> f[MAXN];
    
    void tarjan(int x)
    {
        dfn[x]=low[x]=++tp;
        vis[x]=instack[x]=true;
        s.push(x);
        
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i];
            if(instack[v])
                low[x]=min(low[x],low[v]);
            else if(!vis[v])
                tarjan(v),low[x]=min(low[x],low[v]);
        }
        
        if(low[x]==dfn[x])
        {
            int tmp=-1;cnt++;
            while(tmp!=x)
            {
                tmp=s.top();s.pop();
                instack[tmp]=false;
                col[tmp]=cnt;sum[cnt]++;
            }
        }
    }
    
    void Topo_sort()
    {
        for(int i=1;i<=cnt;i++) f[i][i]=1;
        queue<int> q;
        for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=0;i<G[u].size();i++)
            {
                int v=G[u][i];f[v]|=f[u];
                if(!(--in[v])) q.push(v);
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",dat[i]+1);
            for(int j=1;j<=n;j++)
                if(dat[i][j]=='1') G[i].push_back(j);
        }
        
        for(int i=1;i<=n;i++)
            if(!vis[i]) tarjan(i);
        
        for(int i=0;i<MAXN;i++) G[i].clear();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)    
                if(dat[i][j]=='1' && col[i]!=col[j])    
                    G[col[j]].push_back(col[i]),in[col[i]]++;
        
        Topo_sort();
        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=cnt;j++)
                if(f[i][j]) res+=1ll*sum[i]*sum[j];
        
        printf("%lld",res);
        return 0;
    }
  • 相关阅读:
    面向对象
    数据库,连接查询
    主外键,子查询
    字符串函数
    数据库。模糊查询,聚合函数,时间日期函数
    数据库。增,删,改,查
    数据库
    多窗体及菜单
    winform公共控件及其常用属性
    winform 客户端应用程序(c/s b/s)
  • 原文地址:https://www.cnblogs.com/newera/p/9248715.html
Copyright © 2011-2022 走看看