Description

度量一个有向图联通情况的一个指标时连通数, 指图中可达顶点对的个数.

在上图中, 顶点 \(1\) 可以到达 \(1, 2, 3, 4, 5\);

顶点 \(2\) 可以到达 \(2, 3, 4, 5\);

顶点 \(3\) 可以到达 \(3, 4, 5\);

顶点 \(4, 5\) 均只能到达自身, 所以它的连通数为 \(14\);

Input

输入数据第一行是图顶点的数量, 一个正整数 \(n\).

接下来 \(n\) 行, 每行 \(n\) 个字符. 第 \(i\) 行第 \(j\) 列的 \(1\) 表示顶点 \(i\)\(j\) 有边,\(0\) 则表示无边.

Output

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

Sample Input

3
010
001
100

Sample Output

9

Data Range

对于 100% 的数据,\(n \leq 2000\).

Explanation

输入需要字符串给差评......

题干偷懒只放图差评...... 害得我写题解还得把题干重新抄一遍......

预先处理强连通分量缩点, 然后缩出来的图就一定是一个 DAG 了. 这时用一些奇特的技巧 在这个 DAG 上面瞎搞打标记, 最后可以得到值.

感觉这个和某一年 NOIP 里面的题目很相似啊......

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <stack>
#include <bitset>
#include <cstring>

using namespace std;
typedef long long lli;
const int maxn = 4010, maxm = 4000100;

class Graph
{
public:
    struct edge
    {
        int u, v;
        edge *next;
    };
};

class Tarjan : public Graph
{
public:
    int n, ecnt, dcnt, bcnt;
    edge *edges[maxn], epool[maxm];
    void add_edge(int u, int v)
    {
        edge *p = &epool[++ecnt];
        p->u = u; p->v = v;
        p->next = edges[u]; edges[u] = p;
        return ;
    }
    int dfn[maxn], low[maxn], instk[maxn];
    int belong[maxn], bsize[maxn];
    stack<int> stk;
    void dfs(int p)
    {
        dfn[p] = low[p] = ++dcnt;
        stk.push(p);
        instk[p] = true;
        for (edge *ep = edges[p]; ep; ep = ep->next) {
            int q = ep->v;
            if (!dfn[q]) {
                dfs(q);
                if (low[q] < low[p])
                    low[p] = low[q];
            } else if (instk[q] && dfn[q] < low[p])
                low[p] = dfn[q];
        }
        if (dfn[p] == low[p]) {
            bcnt += 1;
            bsize[bcnt] = 0;
            int q = 0;
            do {
                q = stk.top();
                stk.pop();
                instk[q] = false;
                belong[q] = bcnt;
                bsize[bcnt] += 1;
            } while (q != p);
        }
        return ;
    }
    void init(int n)
    {
        this->n = n;
        return ;
    }
    void eval(void)
    {
        bcnt = dcnt = 0;
        while (!stk.empty())
            stk.pop();
        memset(instk, 0, sizeof(instk));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(belong, 0, sizeof(belong));
        for (int i = 1; i <= n; i++)
            if (!dfn[i])
                dfs(i);
        return ;
    }
} graph;

class TreeDP : public Graph
{
public:
    int n, ecnt;
    int in_degree[maxn];
    edge *edges[maxn], epool[maxm];
    void add_edge(int u, int v)
    {
        edge *p = &epool[++ecnt];
        p->u = u; p->v = v;
        p->next = edges[u]; edges[u] = p;
        in_degree[v] += 1;
        return ;
    }
    void init(int n)
    {
        this->n = n;
        for (int i = 1; i <= n; i++)
            for (edge *ep = graph.edges[i]; ep; ep = ep->next)
                if (graph.belong[i] != graph.belong[ep->v])
                    this->add_edge(graph.belong[ep->v], graph.belong[i]);
        return ;
    }
    // Now we are using some magic STL templates to ease the code.
    bitset<maxn> mark[maxn];
    int eval(void)
    {
        stack<int> stk;
        for (int i = 1; i <= graph.bcnt; i++)
            mark[i].reset();
        for (int i = 1; i <= n; i++)
            mark[graph.belong[i]][i] = true;
        // Pushing stuff into the stack
        for (int i = 1; i <= graph.bcnt; i++)
            if (in_degree[i] <= 0)
                stk.push(i);
        // Evaluating
        while (!stk.empty()) {
            int cur = stk.top();
            stk.pop();
            for (edge *ep = edges[cur]; ep; ep = ep->next) {
                mark[ep->v] |= mark[cur];
                in_degree[ep->v] -= 1;
                if (!in_degree[ep->v])
                    stk.push(ep->v);
            }
        }
        // Getting result
        int res = 0;
        for (int i = 1; i <= graph.bcnt; i++)
            for (int j = 1; j <= n; j++)
                if (mark[i][j])
                    res += graph.bsize[i];
        return res;
    }
} tree;

int n;
char str[maxn];

int main(int argc, char** argv)
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%s", str + 1);
        for (int j = 1; j <= n; j++)
            if (str[j] == '1')
                graph.add_edge(i, j);
    }
    graph.init(n);
    // Resolving graph for SCCs with Tarjan
    graph.eval();
    // Building tree structure with preresolved data upstream from Tarjan
    tree.init(n);
    // Retrieving result
    int res = tree.eval();
    printf("%d\n", res);
    return 0;
}