zoukankan      html  css  js  c++  java
  • 比特镇旅游(Tourist Attractions)【暴力+Bitset 附Bitset用法】

    Online Judge:NOIP2016十连测第一场 T2

    Label:暴力,Bitset

    题目描述

    在美丽的比特镇一共有n个景区,编号依次为1n,它们之间通过若干条双向道路连接。

    Byteasar 慕名来到了比特镇旅游,不过由于昂贵的门票费,他只能负担起 4 个景区的门票费。他可以在任意景区开始游览,然后结束在任意景区。

    Byteasar 的旅游习惯比较特殊,一旦他路过了一个景区,他就一定会进去参观,并且他永远不会参观同一个景区两次。所以他想知道,有多少种可行的旅游路线,使得他可以恰好参观 4 个景区呢?即,有多少条简单路径恰好经过了 4 个点。

    输入

    第一行包含两个整数n,表示景区的总数。

    2至第n+1行,每行一个长度为n01字符串,第i+1行第j个字符为0表示ij之间没有道路,为1表示有一条道路。

    输入数据保证((i,j))的连接情况等于((j,i))的连接情况,且((i,i))恒为0。

    输出

    输出一行一个整数,即可行的路线总数。

    样例

    Input

    4
    0101
    1010
    0101
    1010
    

    Output

    8
    

    说明/提示

    8 条路线分别为:
    1->2->3->4,4->3->2->1,
    2->3->4->1,1->4->3->2,
    3->4->1->2,2->1->4->3,
    4->1->2->3,3->2->1->4。

    对于40%数据,(n<=50)

    对于70%数据,(n<=300)

    对于100%数据,(n<=1500)

    题解

    40pts

    (O(N^4))枚举四个点。

    70pts

    (O(N^3))

    考虑枚举中间两个点(p2,p3),现在要找到符合条件的对数{(p1,p4)}。需要满足的条件是这四个点两两都不相同。

    (cnt[i])表示与i直接连通的点的个数(就是字符串中含1个数),(same[i][j])表示与i,j都直接相连的点的个数(就是两个字符串对应位都为1的位数)。

    那么上面的符合条件的对数{(p1,p4)}就是((cnt[p2]-1)*(cnt[p3]-1)-same[p2][p3])。都减一是因为(p2,p3)互相相连,新选的(p1,p4)不能跟这两个重了。

    上面的枚举是(O(N^2))的,预处理(same[][])(O(N^3))的。

    100pts

    主要瓶颈在于(same[][])的预处理,其实预处理的时候就马上想到用(Bitset)去优化常数,快速得到这个值,但是考试的时候觉得应该有(N^2)解法,结果Claris的正解就是这东西???

    所以利用(Bitset)二进制存储,计算两者与运算结果中1的个数。

    复杂度为(O(frac{n^3}{64})),对于n<=1500的数据没问题。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1510;
    int n,cnt[N];
    bitset<N>a[N];
    int main(){
    	scanf("%d",&n);
    	register int i,j;char c;
    	for(i=1;i<=n;i++)for(j=1;j<=n;j++){
    		c=getchar();
    		while(c!='0'&&c!='1')c=getchar();
    		a[i][j]=c-'0';
    		cnt[i]+=c-'0';
    	}
    	long long ans=0;
    	for(i=1;i<=n;i++)for(j=i+1;j<=n;j++)if(a[i][j]==1){
    		ans+=1ll*(cnt[i]-1)*(cnt[j]-1)-1ll*(a[i]&a[j]).count();
    	}
    	printf("%lld
    ",ans<<1);
    }
    

    END

    整理一下(Bitset)的用法。参考博客->

    定义/初始化

    <>中填的类似数组大小,后面可以开成单个变量,也可以开成一个数组。

    bitset<LEN>a;
    bitset<2333>b[N];
    

    初始化大概有如下几种方式。

     #include<bits/stdc++.h>
     using namespace std;
     int main(){
    	freopen("test.out","w",stdout);
    	//用string(似乎只能包含01,不然运行时会报错)
    	bitset<10>a (string("11011"));
    	cout<<"#1:"<<a<<endl;
    	
    	//用整数(转为二进制)
    	a=123;
    	cout<<"#2:"<<a<<endl;
    
    	//直接像数组那样赋值(下标从0开始,长度为10)
    	for(int i=0;i<=9;i++){
        	int o;scanf("%d",&o);//测试时输入1 0 1 0 0 0 1 1 0 1
        	a[i]=o;
    	}
    	cout<<"#3:"<<a<<endl;
    }
    

    输出结果

    #1:0000011011
    #2:0001111011
    #3:1011000101
    

    运算操作

    (Bitset)支持所有位运算。包括异或^、或|、与&、左移<<、右移>>等。

    常用函数

    查询类

    1.返回1的个数

    a.count();
    

    2.返回是否有1

    a.any();
    

    操作类

    3.全部变成1

    a.set();
    

    4.将右数(i+1)变成1(实际上就是将二进制的第i位变成1,下标从0开始)

    a.set(i);
    //例: a.set(2) 0000000100
    

    5.全部变为0(()中间填数字时指定某一位,同上)

    a.reset();
    

    6.取反(()中间填数字时指定某一位,同上)

    a.flip();
    

    至于常数优化是多少,好像跟机器位数有关(32/64)。

  • 相关阅读:
    字符串的全排列

    链表
    青蛙跳一格或者两格,n格跳法
    二叉树
    Concurrent实现原理
    sql语句总结 (转) http://blog.csdn.net/fengfeng91/article/details/15029173
    ArrayList实现原理
    java虚拟机 内存分配
    【转】关于Quartus ii无法识别Modelsim路径的问题
  • 原文地址:https://www.cnblogs.com/Tieechal/p/11545130.html
Copyright © 2011-2022 走看看