BZOJ2208 [Jsoi2010]连通数[缩点/Floyd传递闭包+bitset优化]
显然并不能直接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优化]的更多相关文章
- [bzoj2208][Jsoi2010]连通数_bitset_传递闭包floyd
连通数 bzoj-2208 Jsoi-2010 题目大意:给定一个n个节点的有向图,问每个节点可以到达的点的个数和. 注释:$1\le n\le 2000$. 想法:网上有好多tarjan+拓扑序dp ...
- 2018.09.11 bzoj2208: [Jsoi2010]连通数(bitset+floyd)
传送门 听说正解是缩点+dfs? 直接bitset优化floyd传递闭包就行了.(尽管时间复杂度是假的O(n3/32)" role="presentation" styl ...
- BZOJ2208: [Jsoi2010]连通数(tarjan bitset floyd)
题意 题目链接 Sol 数据水的一批,\(O(n^3)\)暴力可过 实际上只要bitset优化一下floyd复杂度就是对的了(\(O(\frac{n^3}{32})\)) 还可以缩点之后bitset维 ...
- bzoj2208 [Jsoi2010]连通数(scc+bitset)
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1879 Solved: 778[Submit][Status ...
- [BZOJ2208]:[Jsoi2010]连通数(暴力 or bitset or 塔尖?)
题目传送门 题目描述 度量一个有向图连通情况的一个指标是连通数,指图中可达顶点对的个数. 在上图中,顶点1可以到达1.2.3.4.5. 顶点2可以到达2.3.4.5. 顶点3可以到达3.4.5. 顶点 ...
- [BZOJ2208][Jsoi2010]连通数 暴力枚举
Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图 ...
- BZOJ2208: [Jsoi2010]连通数
tarjan缩点后拓扑排序,每一个点用一个bitset记录哪些点能到达它. PS:数据太水,暴力能过. #include<bits/stdc++.h> using namespace st ...
- POJ 3275 Ranking the cows ( Floyd求解传递闭包 && Bitset优化 )
题意 : 给出 N 头牛,以及 M 个某些牛之间的大小关系,问你最少还要确定多少对牛的关系才能将所有的牛按照一定顺序排序起来 分析 : 这些给出的关系想一下就知道是满足传递性的 例如 A > B ...
- HDU 5036 Explosion (传递闭包+bitset优化)
<题目链接> 题目大意: 一个人要打开或者用炸弹砸开所有的门,每个门后面有一些钥匙,一个钥匙对应一个门,告诉每个门里面有哪些门的钥匙.如果要打开所有的门,问需要用的炸弹数量为多少. 解题分 ...
随机推荐
- MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)
本节内容: 1)索引基础 2)索引类型(Hash索引.有序数组.B+树) 3)索引的几个常见问题 1)联合索引 2)最左前缀原则 3)覆盖索引 4)索引下推 1. 索引基础 索引对查询的速度有着至关重 ...
- 常用的API
API (application programming Interface)应用程序编程接口 java 是字典 Scanner类的功能可以实现从键盘输入到程序当中. 引用类型的一般使用步骤 ·1导包 ...
- Design In-Memory File System
Design an in-memory file system to simulate the following functions: ls: Given a path in string form ...
- 【转帖】Webmin 安装 (centos7 rpm 方式)
https://www.cnblogs.com/osfipin/p/5948803.html 这两天公众号都在手这个小工具, 今天早上试了下 挺好用的 还看到了启动 samba 的方法. 一会儿 再学 ...
- 操作MySQL数据进行记录的随意排序
说到排序,想必大家都知道MySQL中的“ORDER BY”这个关键词吧,使用它可以实现查询数据根据某一字段(或多个字段)的值排序,那么如何实现数据的任意排序操作呢? 其实这里我所说的“随意排序”,本质 ...
- Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制
服务模型 首先,Istio作为一个(微)服务治理的平台,和其他的微服务模型一样也提供了Service,ServiceInstance这样抽象服务模型.如Service的定义中所表达的,一个服务有一个全 ...
- gdb暂停或恢复程序的运行
ref : https://blog.csdn.net/seu_lyr/article/details/9050657 一 暂停程序的运行: (一)GDB的暂停方式:断点(BreakPoint). ...
- MySQL设置自增字段
1.MySQL每张表只能有1个自增字段,这个自增字段即可作为主键,也可用作非主键使用,但是请注意将自增字段当做非主键使用时必须为其添加唯一索引,否则系统将会报错 )将自动增长字段设置为主键 CREAT ...
- Swagger学习(三、配置扫描接口)
生产环境中使用,发布的时候不能使用
- spark2.0的10个特性介绍
1. Spark 2.0 ! 还记得我们的第七篇 Spark 博文里吗?里面我用三点来总结 spark dataframe 的好处: 当时是主要介绍 spark 里的 dataframe,今天是想总结 ...