zoukankan      html  css  js  c++  java
  • 简单路径-bitset初体验

    题目描述

    给定一个nn个点的无向图,求这个图中有多少条长度为4的简单路径。
    n1500

    输入

    第一行一个数n
    接下来n行每行n个0或1
    第i行第j列是1表示i与j联通

    输出

    输出简单路径的个数

    样例输入

    5 00011 00000 00010 10100 10000

    样例输出

    2

    提示

    n<=1500

     
     
    复制一下cgt大佬的ppt(未经授权hhh)

    O(n^4)
    不会做??
    你可以离开这个教室了
    暴力枚举四个城市即可
    O(n^3)
    70分做法:设经过的点为a-b-c-d,枚举中间边b-c,再枚举与b,c相连的点,设deg x 表示点x的度数,那么边b-c对答案的贡献为(du[b]-1)(du[c]- 1) - 经过b-c这条边的三元环个数。 计算三元环的个数只需要枚举除b,c之外的另一个点即可,时间复杂度O(n^3)
    70分算法的瓶颈在于三元环计数
    那如何解决呢

    so easy
    我们能想到压位
    记s[i][1]为i和1~32的状态
    第x位上是1的话就说明它和x号城市有连边
    s[i][2]为i和33~64号……以此类推
    i点和j点形成三元环的个数s可以这样写出
    for k=1 ~ n/32  s=s+(s[i][k]&s[j][k] 中1的个数)
    前面提到统计1的个数可以预处理出
    所以时间复杂度变为了O(n^3 / 32)
    n=1500时大约为1s
    因此我们小小地使用了一个压位技巧便能AC此题
    题目源JZOJ4857

    所以我开始了手动bitset(程序灰常的丑嘤嘤嘤)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int a[1605][1605],s[1600][50],f[1605],b[66000];
    int main()
    {
        int n;
        scanf("%d",&n);
        for (int i=1;i<(1<<16);i++) b[i]=b[i>>1]+(i&1);
            
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=n;j++)
            {
                scanf("%1d",&a[i][j]);
                if (a[i][j]==1) 
                {
                    f[i]++;
                }
            }
         }
         
        for (int i=1;i<=n;i++)
            for (int j=1;j<=(n-1)/30+1;j++)
                for (int k=(j-1)*30+1;k<=j*30;k++)
                    s[i][j]=(s[i][j]<<1)|a[i][k];
        ll num=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            {
                if (a[i][j]==1)
                    {
                        for (int k=1;k<=(n-1)/30+1;k++) 
                        {
                            int xx=s[i][k]&s[j][k];
                            int xxx=xx>>16;
                            xx=xx&((1<<16)-1);
                            num=num-b[xxx]-b[xx];
                        }
                         num=num+(f[i]-1)*(f[j]-1);
                    }
            }
        printf("%lld",num);
    }

    然而我发现c++这种神奇的东西还有美丽的bitset,于是不用白不用哈

    #include<bits/stdc++.h>
    using namespace std;
    bitset<1600>a[1600];
    int num[1600];
    int main()
    {
        int n;
        long long sum;
        cout<<sum;
        scanf("%d",&n);
        for (int i=0;i<n;i++) cin>>a[i];
        for (int i=0;i<n;i++) num[i]=a[i].count();
        for (int i=0;i<n;i++) 
            for (int j=0;j<n;j++) 
                if ((i!=j)&&(a[i][n-j-1]==1)) 
                {
                    sum=sum+(num[i]-1)*(num[j]-1)-(a[i]&a[j]).count();
                }
        printf("%lld",sum);
        return 0;
    }

    是不是很简单呢啦啦啦。

    就是酱紫。

    真是充实的一天哇。

    还充实巩固了RMQ

        for (int j=1;j<=20;j++)
            for (int i=1;i+(1<<j)-1<=n;i++)
                f1[i][j]=max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]);
        
  • 相关阅读:
    点击事件
    php if语句判定my查询是否为空
    php if语句判定ms查询是否为空
    thinkphp 原生sql使用分页类
    从JAVA客户端访问Redis示例(入门)
    Log4j日志级别
    网页正文抽取(包含提取图片)
    网络爬虫基本原理
    Java中替换HTML标签的方法代码
    Java/Js下使用正则表达式匹配嵌套Html标签
  • 原文地址:https://www.cnblogs.com/Hathawaxy/p/9268907.html
Copyright © 2011-2022 走看看