• bzoj2208 [Jsoi2010]连通数(scc+bitset)


    2208: [Jsoi2010]连通数

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 1879  Solved: 778
    [Submit][Status][Discuss]

    Description

    Input

    输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。

    Output

    输出一行一个整数,表示该图的连通数。

    Sample Input

    3
    010
    001
    100

    Sample Output

    9

    HINT

    对于100%的数据,N不超过2000。

    Source

    【思路】

        强连通分量+bitset传递闭包。

        求出scc,缩点。对于新的DAG,如果两个scc之间相连则ans+=sccsz[i]*sccsz[j]。利用bitset与递推判断相连。

    【代码】

     1 #include<cstdio>
     2 #include<bitset>
     3 #include<queue>
     4 #include<stack>
     5 #include<vector>
     6 #include<cstring>
     7 #include<iostream>
     8 using namespace std;
     9 
    10 const int maxn = 2000+10;
    11 
    12 int pre[maxn],lowlink[maxn],sccno[maxn],sccsz[maxn],dfs_clock,scc_cnt;
    13 vector<int> G[maxn];
    14 stack<int> S;
    15 
    16 int dfs(int u) {
    17     pre[u]=lowlink[u]=++dfs_clock;
    18     S.push(u);
    19     for(int i=0;i<G[u].size();i++) {
    20         int v=G[u][i];
    21         if(!pre[v]) {
    22             dfs(v);
    23             lowlink[u]=min(lowlink[u],lowlink[v]);
    24         }
    25         else if(!sccno[v]) {
    26             lowlink[u]=min(lowlink[u],pre[v]);
    27         }
    28     }
    29     if(lowlink[u]==pre[u]) {
    30         scc_cnt++;
    31         for(;;) {
    32             int x=S.top(); S.pop();
    33             sccno[x]=scc_cnt;
    34             sccsz[scc_cnt]++;
    35             if(x==u) break;
    36         }
    37     }
    38 }
    39 void find_scc(int n) {
    40     memset(pre,0,sizeof(pre));
    41     memset(sccsz,0,sizeof(sccsz));
    42     memset(sccno,0,sizeof(sccno));
    43     scc_cnt=dfs_clock=0;
    44     for(int i=0;i<n;i++)  
    45         if(!pre[i]) dfs(i);
    46 }
    47 
    48 bitset<maxn> f[maxn];    //使用bitset 
    49 int n,in[maxn];
    50 char s[maxn];
    51 
    52 vector<int> Gx[maxn];
    53 void rebuild() {
    54     for(int i=1;i<=scc_cnt;i++) in[i]=0;
    55     for(int i=0;i<n;i++) {
    56         int u=sccno[i];
    57         for(int j=0;j<G[i].size();j++) {
    58             int v=sccno[G[i][j]];
    59             if(u!=v) Gx[u].push_back(v),in[v]++;
    60         }
    61     }
    62 }
    63 
    64 queue<int> q;
    65 void solve() {
    66     for(int i=1;i<=scc_cnt;i++) f[i][i]=1;
    67     for(int i=1;i<=scc_cnt;i++) if(!in[i]) q.push(i);
    68     while(!q.empty()) {
    69         int u=q.front(); q.pop();
    70         for(int i=0;i<Gx[u].size();i++) {
    71             int v=Gx[u][i];
    72             f[v]|=f[u];            //传递闭包
    73             if((--in[v])==0)  q.push(v);
    74         }
    75     }
    76 }
    77 
    78 int main() {
    79     scanf("%d",&n);
    80     for(int i=0;i<n;i++){
    81         scanf("%s",s);
    82         for(int j=0;j<n;j++) {
    83             if(s[j]-'0') G[i].push_back(j);
    84         }
    85     }
    86     find_scc(n);
    87     rebuild();
    88     solve();
    89     int ans=0;
    90     for(int i=1;i<=scc_cnt;i++)
    91     {
    92         for(int j=1;j<=scc_cnt;j++)
    93             if(f[i][j]) ans+=sccsz[i]*sccsz[j];
    94     }
    95     printf("%d
    ",ans);
    96     return 0;
    97 }
  • 相关阅读:
    使用Visual Studio .Net 做自己的汉化软件
    给所有的Control加两个属性,实现回车键自动跳转到下一个控件
    数字逗号标记—以前原创(一)
    解决w3wp.exe占用CPU和内存问题
    sql日期函数
    索引的使用总结
    w3wp.exe狂占内存
    w3wp.exe占内存CPU问题 WIN2003 IIS6.0假死现象的分析
    查看Linux系统日志
    linux动态增加LV空间
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5057217.html
Copyright © 2020-2023  润新知