其他分享
首页 > 其他分享> > 洛谷 P4306 [JSOI2010]连通数 - 图论、统计

洛谷 P4306 [JSOI2010]连通数 - 图论、统计

作者:互联网

洛谷 P4306 [JSOI2010]连通数

题目链接:洛谷 P4306 [JSOI2010]连通数

算法标签: 图论统计

题目

题目描述

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

如图

洛谷 P4306 [JSOI2010]连通数 p1

顶点 1 可达 1, 2, 3, 4, 5

顶点 2 可达 2, 3, 4, 5

顶点 3 可达 3, 4, 5

顶点 4, 5 都只能到达自身。

所以这张图的连通数为 14。

给定一张图,请你求出它的连通数

输入格式

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

输出格式

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

输入输出样例

输入 #1

3
010
001
100

输出 #1

9

说明/提示

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

题解:

某机房巨佬JZYshuraK_彧 推荐的题,貌似说有很多做法,不过作为一个蒟蒻,我搬出了许久没有用到的 毒瘤 SPFA,思路是将SPFA中的松弛更新最短路改为连通计数,最终统计\(ans\)即可。

大致实现如下(链式前向星存图):

void spfa(int s)
{
    memset(vis, 0, sizeof vis);
    queue <int> q;
    q.push(s);
    vis[s] = 1;
    while(!q.empty())
    {
        int x, y;
        x = q.front();
        q.pop();
        for (int i = head[x]; i; i = nex[i])
        {
            y = to[i];
            if (!vis[y])
            {
                q.push(y);
                vis[y] = 1;
                ans ++ ;
            }
        }
    }

}

之后按照操作统计答案即可,不过本题有毒瘤坑点。

本题坑点:

  1. 所读入矩阵之中没有空格,需要按照字符串读入在处理(被疯狂卡)
  2. 在输出的时候要记录\(ans + n\),原因在于这道题当中,自身与自身被算作连通,而在跑SPFA时候是没有记录自己的。

由于一个01串,假设为\(011111000001\) ,在这道题的题目下可以很简单的处理为\(0101\)这样一个串,在进行两种操作取最小值。

仔细分析这两种操作的时候,我们可以得到以下结论:

由此此题得解,注意本题数据需要开long long

AC代码

#include <bits/stdc++.h>

using namespace std;

const int N = 2020;
const int M = N * N;

int n, ans, vis[N];
int tot, to[M], nex[M], head[N];

void add(int x, int y)
{
    to[++tot] = y;
    nex[tot] = head[x];
    head[x] = tot;
}
void spfa(int s)
{
    memset(vis, 0, sizeof vis);
    queue <int> q;
    q.push(s);
    vis[s] = 1;
    while(!q.empty())
    {
        int x, y;
        x = q.front();
        q.pop();
        for (int i = head[x]; i; i = nex[i])
        {
            y = to[i];
            if (!vis[y])
            {
                q.push(y);
                vis[y] = 1;
                ans ++ ;
            }
        }
    }

}
int main()
{
    scanf("%d", &n);
    char ch[2020];
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%s", ch + 1);
        for (int j = 1; j <= n; j ++ )
        {
            if (ch[j] == '1')
                add(i, j);
        }
    }
    for (int i = 1; i <= n; i ++ )
        spfa(i);

    printf("%d", ans + n);
    return 0;
}

标签:JSOI2010,head,洛谷,int,vis,连通数,ans,顶点
来源: https://www.cnblogs.com/littleseven777/p/11851759.html