bzoj2208:[Jsoi2010]连通数

http://blog.csdn.net/u013598409/article/details/47037499 里面似乎有生成数据的。。。
//我本来的想法是tarjan缩点之后然后将图遍历一遍就可以了,复杂度应该是O(n2)的,为什么说这样是n3的啊。。。
//=>这种做法是错的因为有可能会重复计算用一下传递闭包就可以了然而直接递推以前写的dfsqaq
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<stack>
#include<vector>
#include<queue>
#include<bitset>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define qwq(x) for(edge *o=head[x];o;o=o->next)
const int nmax=2e3+5;
const int maxn=nmax*nmax;
const int inf=0x7f7f7f7f;
struct edge{
    int to;edge *next;
}; 
edge es[maxn],*pt=es,*head[nmax];
void add(int u,int v){
    pt->to=v;pt->next=head[u];head[u]=pt++;
}
char ch[nmax];
int pre[nmax],scc_cnt,dfs_clock,sm[nmax],scc[nmax];
stack<int>s;
void mins(int &a,int b){
    if(a>b) a=b;
}
int dfs(int x){
    int lowu=pre[x]=++dfs_clock;s.push(x);
    qwq(x){
        if(!pre[o->to]) mins(lowu,dfs(o->to));
        if(!scc[o->to]) mins(lowu,pre[o->to]);
    }
    if(lowu==pre[x]){
        scc_cnt++;int o,cnt=0;
        while(1){
            o=s.top();s.pop();
            scc[o]=scc_cnt;++cnt;
            if(o==x) break;
        }
        sm[scc_cnt]=cnt;
    }
    return lowu;
}
bitset<nmax>a[nmax];
int in[nmax];vector<int>g[nmax];queue<int>q;
int main(){
    int n,u,v,d;scanf("%d",&n);
    rep(i,1,n){
        scanf("%s",ch+1);
        rep(j,1,n) if(ch[j]=='1') add(i,j);
    }
    rep(i,1,n) if(!pre[i]) dfs(i);
     
    rep(i,1,n) {
        u=scc[i];
        qwq(i) if(u!=(v=scc[o->to])) g[u].push_back(v),++in[v];
    }
    rep(i,1,scc_cnt) a[i][i]=1;
    rep(i,1,scc_cnt) if(!in[i]) q.push(i);
    while(!q.empty()){
        u=q.front();q.pop();
        if(!g[u].size()) continue;
        rep(i,0,g[u].size()-1){
            v=g[u][i];
            a[v]|=a[u]; //a保存的是可以到达该强联通分量的 
            if(!--in[v]) q.push(v);
        }
    }
    int ans=0;
    rep(i,1,scc_cnt) rep(j,1,scc_cnt) if(a[i][j]) ans+=sm[i]*sm[j];
    printf("%d\n",ans);
    return 0;
}

2208: [Jsoi2010]连通数

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2249  Solved: 965
[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

[Submit][Status][Discuss]
posted @ 2016-09-09 21:15  BBChq  阅读(174)  评论(0编辑  收藏  举报