BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset

来源:互联网 发布:二手mac pro工作站 编辑:程序博客网 时间:2024/06/06 00:48

题目大意:给出一张有向图,若一个点能够到达另一个点,那么说这两个点是一对联通点。问图中共有多少联通点。


思路:先进行一次Tarjan,求出所有的scc,对于一个scc中的点,对答案的贡献就是cnt^2,不同的scc组成了一张可拓扑图,然后对于每个scc维护一个bitset,来统计他自己和标号比它小的scc中共有多少个不同的点。然后进行dp,其中不停的或就可以了。

第一次使用bitset


CODE:


#include <bitset>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAXP 2010#define MAX 4000010using namespace std; int points;int head[MAXP],total;int next[MAX],aim[MAX]; inline void Add(int x,int y){    next[++total] = head[x];    aim[total] = y;    head[x] = total;} int dfn[MAXP],low[MAXP],_clock;int stack[MAXP],top;bool in_stack[MAXP];int changed[MAXP],scc,num[MAXP];bitset<MAXP> have[MAXP]; void Tarjan(int x){    dfn[x] = low[x] = ++_clock;    stack[++top] = x;    in_stack[x] = true;    for(int i = head[x]; i; i = next[i]) {        if(!dfn[aim[i]])            Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]);        else if(in_stack[aim[i]])            low[x] = min(low[x],dfn[aim[i]]);    }    if(dfn[x] == low[x]) {        int temp;        ++scc;        do {            temp = stack[top--];            in_stack[temp] = false;            changed[temp] = scc;            ++num[scc];        }while(temp != x);    }} int main(){    cin >> points;    for(int i = 1; i <= points; ++i)        for(int x,j = 1; j <= points; ++j) {            scanf("%1d",&x);            if(x)   Add(i,j);        }    for(int i = 1; i <= points; ++i)        if(!dfn[i]) Tarjan(i);    for(int i = 1; i <= points; ++i)        have[changed[i]][i] = true;    int ans = 0;    for(int i = 1; i <= scc; ++i) {        ans += num[i] * num[i];        bitset<MAXP> temp;        for(int x = 1; x <= points; ++x)            if(changed[x] == i)                for(int j = head[x]; j; j = next[j])                    if(changed[aim[j]] != i)                        temp |= have[changed[aim[j]]];        ans += num[i] * temp.count();        have[i] |= temp;    }    cout << ans << endl;    return 0;}


0 0
原创粉丝点击