显然并不能直接dfs,因为$m$会非常大,复杂度就是$O(mn)$;

这题有三种做法,都用到了bitset的优化。第二种算是一个意外的收获,之前没想到竟然还有这种神仙操作。。


方法一:缩点+DAG上bitset优化的统计

做有向图连通问题上来先看可不可以缩点首先一个环内点是可以相互连通的,又发现DAG也许方便统计,于是缩点。。然后变成一张DAG,只要统计每个点可以往后走到的所有点权(指该环包含的点数)的和。并不好直接把后继全加上去,因为会有点被重复统计。为了避免重复统计,只要直接每个点开一个bitset,表示他能走到哪些点,这样dp的时候直接对儿子取or就可以了,然后再统计,不会重复。复杂度$O(\frac{mn}{32})$。实际上是可以卡过去的。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<bitset>
#define mst(x) memset(x,0,sizeof x)
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+;
struct thxorz{
int to[N*N],nxt[N*N],head[N],tot;
inline void add(int x,int y){to[++tot]=y,nxt[tot]=head[x],head[x]=tot;}
}G1,G2;
int from[N*N];
char s[N];
int n,m,ans;
#define y G1.to[j]
int dfn[N],low[N],tim,stk[N],instk[N],bel[N],sum[N],val[N],Top;
void tarjan(int x){
dfn[x]=low[x]=++tim,stk[++Top]=x,instk[x]=;
for(register int j=G1.head[x];j;j=G1.nxt[j]){
if(!dfn[y])tarjan(y),MIN(low[x],low[y]);
else if(instk[y])MIN(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
int tmp;
do instk[tmp=stk[Top--]]=,bel[tmp]=x,++sum[x];while(tmp^x);
}
}
#undef y
#define y G2.to[j]
bitset<N> S[N];
void dp(int x){
if(val[x])return;
S[x][x]=;
for(register int j=G2.head[x];j;j=G2.nxt[j])dp(y),S[x]|=S[y];
for(register int i=;i<=n;++i)if(S[x][i])val[x]+=sum[i];
val[x]=val[x]*sum[x];
}
#undef y
int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
read(n);
for(register int i=;i<=n;++i){
scanf("%s",s+);
for(register int j=;j<=n;++j)if(i^j&&s[j]=='')G1.add(i,j),from[G1.tot]=i;
}
for(register int i=;i<=n;++i)if(!dfn[i])tarjan(i);
for(register int t=,x,y;t<=G1.tot;++t){
x=from[t],y=G1.to[t];
if(bel[x]^bel[y])G2.add(bel[x],bel[y]);
}
for(register int i=;i<=n;++i)dp(i),ans+=val[i];
printf("%d\n",ans);
return ;
}

方法二:Floyd传递闭包+bitset优化

这个优化真是妙啊,之前学Floyd都没想过这个优化。`````

连通性可以用二元逻辑关系表示,也就是可以用Floyd来做传递闭包。具体来说,就是设$f_{i,j}=0/1$表示$i$到$j$是否可达。然后转移的话是$\text{f[i][j]|=f[i][k]&f[k][j]}$。

注意这个转移。$f_{i,j}$相当于看成对于$i$点,用一个bitset表示他到$1\sim n$各点的可达性。

再观察,$f[i][k]$值已经是定的了,如果是$0$就不转移了,是$1$的话,对于每一位$j$,只要用$f[k]$对应的$j$位or一下就可以了。并且$f[i][k]$在本次转移中是不会变的。

所以,直接用bitset整体进行or操作就行了。$O(\frac{n^3}{32})$。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<bitset>
#define mst(x) memset(x,0,sizeof x)
#define dbg(x) cerr << #x << " = " << x <<endl
#define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,):;}
template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,):;}
template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+;
bitset<N> f[N];
int n,ans;
char s[N]; int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
read(n);
for(register int i=;i<=n;++i){
scanf("%s",s+);
for(register int j=;j<=n;++j)f[i][j]=s[j]==''||i==j;
}
for(register int k=;k<=n;++k)
for(register int i=;i<=n;++i)
if(f[i][k])f[i]|=f[k];
for(register int i=;i<=n;++i)ans+=f[i].count();
return printf("%d\n",ans),;
}

方法三:暴力BFS+bitset标记松弛点(手写警告)

对每一个点,直接开始BFS,然后这个做法时间瓶颈在于每次都要枚举到所有边,那么我么尽量让他BFS时候从松弛点去走没有被访问过的点,避免走路径通向访问过的点的。可以用bitset维护目前所有点哪些没有被访问过,每个节点再开一个bitset表示他通往哪些点,每次BFS松弛的时候,把两者and一下,这样所有的$1$位就是没有访问过的,取出这些$1$,访问之即可。这样,就使得走过的边数量与点数相同,复杂度就降成了$O(n(\frac{n^2}{32}+n))$。不过,这种方法由于要取出$1$,如果直接对bitset每一位直接检验,复杂度就又回去了,而STL的bitset太垃圾没有这个取$1$复杂度和$1$数量相同的方法,所以我们要手写bitset。。。这种方法是yql讲过的,由于我太菜了,所以我不会写,实际要咕咕咕。

BZOJ2208 [Jsoi2010]连通数[缩点/Floyd传递闭包+bitset优化]的更多相关文章

  1. [bzoj2208][Jsoi2010]连通数_bitset_传递闭包floyd

    连通数 bzoj-2208 Jsoi-2010 题目大意:给定一个n个节点的有向图,问每个节点可以到达的点的个数和. 注释:$1\le n\le 2000$. 想法:网上有好多tarjan+拓扑序dp ...

  2. 2018.09.11 bzoj2208: [Jsoi2010]连通数(bitset+floyd)

    传送门 听说正解是缩点+dfs? 直接bitset优化floyd传递闭包就行了.(尽管时间复杂度是假的O(n3/32)" role="presentation" styl ...

  3. BZOJ2208: [Jsoi2010]连通数(tarjan bitset floyd)

    题意 题目链接 Sol 数据水的一批,\(O(n^3)\)暴力可过 实际上只要bitset优化一下floyd复杂度就是对的了(\(O(\frac{n^3}{32})\)) 还可以缩点之后bitset维 ...

  4. bzoj2208 [Jsoi2010]连通数(scc+bitset)

    2208: [Jsoi2010]连通数 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1879  Solved: 778[Submit][Status ...

  5. [BZOJ2208]:[Jsoi2010]连通数(暴力 or bitset or 塔尖?)

    题目传送门 题目描述 度量一个有向图连通情况的一个指标是连通数,指图中可达顶点对的个数. 在上图中,顶点1可以到达1.2.3.4.5. 顶点2可以到达2.3.4.5. 顶点3可以到达3.4.5. 顶点 ...

  6. [BZOJ2208][Jsoi2010]连通数 暴力枚举

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

  7. BZOJ2208: [Jsoi2010]连通数

    tarjan缩点后拓扑排序,每一个点用一个bitset记录哪些点能到达它. PS:数据太水,暴力能过. #include<bits/stdc++.h> using namespace st ...

  8. POJ 3275 Ranking the cows ( Floyd求解传递闭包 && Bitset优化 )

    题意 : 给出 N 头牛,以及 M 个某些牛之间的大小关系,问你最少还要确定多少对牛的关系才能将所有的牛按照一定顺序排序起来 分析 : 这些给出的关系想一下就知道是满足传递性的 例如 A > B ...

  9. HDU 5036 Explosion (传递闭包+bitset优化)

    <题目链接> 题目大意: 一个人要打开或者用炸弹砸开所有的门,每个门后面有一些钥匙,一个钥匙对应一个门,告诉每个门里面有哪些门的钥匙.如果要打开所有的门,问需要用的炸弹数量为多少. 解题分 ...

随机推荐

  1. Java学习笔记-包,classpath,import,jar

    这里介绍Java的包,classpath,import和jar 包(package) 对类文件进行分类管理 给类提供多层命名空间 写在程序文件的第一行 类名的全称的是 包名.类名 包也是一种封装形式 ...

  2. 第07组 Alpha冲刺(1/4)

    队名:秃头小队 组长博客 作业博客 组长徐俊杰 过去两天完成的任务:完成人员分配,初步学习Android开发 Github签入记录 接下来的计划:继续完成Android开发的学习,带领团队进行前后端开 ...

  3. H3C 交换机配置ssh登陆

    1.开启ssh服务,创建密钥. <D05-S5048-02>system-view [D05-S5048-02]ssh server enable //开启ssh服务 [D05-S5048 ...

  4. IDEA插件之alibaba编程规范

    1.做什么 这是阿里巴巴的编码规范插件,规范内容可以查阅 https://github.com/alibaba/p3c/blob/master/阿里巴巴Java开发手册(华山版).pdf 2.File ...

  5. Pebbles HDU 2167

    Pebbles HDU 2167 大意:给定一个N*N的方格,让你在里面取出一些数使其和最大,要求每一个数不能与其相邻的8个数同时取出. 思路:和炮兵阵地那一题有点像,但我们只需要考虑上一行的情况,这 ...

  6. python+pycharm+django admin css样式出问题

    最近打算学习一下Python,基础知识有了大概的了解,想上手搞搞东西. 我用的python 3.5+pycharm+django 1.11.2 在使用Django,打开127.0.0.1:8000/a ...

  7. Python第三方库资源

    [转载]Python第三方库资源   转自:https://weibo.com/ttarticle/p/show?id=2309404129469920071093 参考:https://github ...

  8. javascript 的惯性运动

    移动端的惯性运动,最早来自 ios 的专利.用于手指滑动,离开屏幕之后,屏幕内容继续滚动.更有动态感. 这里,以 pc 端,鼠标横向(沿x轴) 拖拽的,惯性计算.移动端同理 具体代码如下: <! ...

  9. Wannafly挑战赛22

    B. 字符路径 给一个含n个点m条边的有向无环图(允许重边,点用1到n的整数表示),每条边上有一个字符,问图上有几条路径满足路径上经过的边上的字符组成的的字符串去掉空格后以大写字母开头,句号 '.' ...

  10. 微信公众号支付备忘及填坑之路-java

    一.背景 最近公司给第三方开发了一个公众号,其中最重要的功能是支付,由于是第一次开发,遇到的坑特别的多,截止我写博客时,支付已经完成,在这里我把遇到的坑记录一下(不涉及退款).不得不吐槽一下,腾讯这么 ...