• 小Z爱图论(NOIP信(sang)心(bin)赛)From FallDream


    题目:

    小Z最近喜欢上了图论,于是他研究了一下图的连通性问题。但是他遇到了一个难题。

            给定一个n个点的有向图,求有多少点对(i,j)满足从i点出发能到达点j ?

            小Z仅会简单的朴素算法,所以他想问问你怎么解决。

            你能帮帮他吗?

    输入/输出格式

     第一行一个数字n,表示有n个点。

     接下来n行,每行n个0/1,如果第i行第j个是1,表示从第i个点向第j个点有连边。

            输出仅包含一个数,表示满足条件的点对数量。

    样例输入/输出

    Input:

    3

    0 1 0

    0 0 1

    1 0 0

    Output:

    9

    样例解释

           从任意一个点出发均可到达其它所有点(包括自己)

    数据范围与约定

          对于50%的数据,满足n<=500

           对于100%的数据,满足n<=2000

           注意i和j可以相同

    好吧,大家一看到这道题,心想:有向图判断连通,SB都会(蒟蒻瑟瑟发抖)。。

    然后我们看到了数据范围。。

    恩。。

    好像O(n^3)不能过?

    然后N(n^2logn)就能过了?

    然后各种奇特算法就冒了出来。。

    计算强联通分量。。。(tarjan+拓补?(by hzwer))

    结果蒟蒻认为非常的难,就写了个暴力,拿了40分、

    结果学长给出正解。

    floyd....

    floyd?不会T?

    是的,不会T,因为我们拥有了一个新数据结构!

    BITSET!!!!

    科普一下。

    首先用bitset要#include<bitset>

    同时要定义的时候要这么写:bitset<位数> 名称([数组]可加可不加)

    先来理解一下bitset到底是什么东东。

    众所周知,1个bool值有2种可能 0或1

    那么一个bitset就像是n个bool值用二进制叠了起来,如:001010

    所以还是O(N)啊?

    不对,因为一个二进制数为1bit

    而一个int为32bit

    所以复杂度为O(N^3)/32

    神奇的过了。。

    然后再来讲一讲具体的应用

    首先bitset最常用的就是count()函数,他能找出bitset中1的数量(复杂度玄学)

    本题中我们将floyd简化

    原来3个循环,现在2个。

    bitset<2005> b[2005]

    for(int i=1;i<=n;i++)

    for(int j=1;j<=n;j++)

    if(b[j][i])b[j]|=b[i];

    就是说如果j能走到i,那么i能走到的地方j一定能走到。

    最后统计答案即可(b[i].count()的函数返回值即为i能到达的点的个数(包括i自己))

    下面贴代码

    #include<iostream>
    #include<cstdio>
    #include<bitset>
    #define r register 
    using namespace std;
    bitset<2005> b[2005];
    int n;
    int ans;
    int main(){
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        scanf("%d",&n);
        for(r int i=1;i<=n;i++)
            for(r int j=1;j<=n;j++)
            {
                int x;
                scanf("%d",&x);
                b[i][j]=(x|(i==j));
            }
        for(r int i=1;i<=n;i++)
        for(r int j=1;j<=n;j++)
        if(b[j][i])b[j]|=b[i];
        for(r int i=1;i<=n;i++)
        ans+=b[i].count();
        printf("%d
    ",ans);
        fclose(stdin);
        fclose(stdout);
    }
  • 相关阅读:
    20160220.CCPP体系详解(0030天)
    20160219.CCPP体系详解(0029天)
    20160217.CCPP体系详解(0027天)
    Discuz 如何开启 memcache
    20160216.CCPP体系详解(0026天)
    20160215.CCPP体系详解(0025天)
    Linux之父:诺基亚更应选择 Android 平台
    Linux 之父 Linus 的 8 个趣闻轶事
    Linux 中识别 USB 设备名字的 4 种方法
    码农们加班是“心甘情愿”吗?都是被“逼”的
  • 原文地址:https://www.cnblogs.com/ghostfly233/p/6889846.html
Copyright © 2020-2023  润新知