[BZOJ2208]:[Jsoi2010]连通数(暴力 or bitset or 塔尖?)
题目传送门
题目描述
度量一个有向图连通情况的一个指标是连通数,指图中可达顶点对的个数。
在上图中,顶点1可以到达1、2、3、4、5。
顶点2可以到达2、3、4、5。
顶点3可以到达3、4、5。
顶点4、5均只能到达自身,所以它的连通数为14。
请编写一个程序,输入一个图,求它的连通数。
输入格式
输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。
输出格式
输出一行一个整数,表示该图的连通数。
样例
样例输入:
3
010
001
100
样例输出:
9
数据范围与提示
对于100%的数据,N不超过2000。
题解
千万不要以为这道题数据范围N≤2000就可以暴力,N≤2000意味着最多会有$N^{2}$条边,dfs一遍遍历时间复杂度为边数,那么这道题就会被卡成$N^{3}$。
不过由于数据比较水,暴力卡常也可以A掉……
然而,占用评测资源显然是一种rp--的行为,所以考虑优化。
bitset!!!
利用floyed的思想。
空间和时间都在很大程度上得到了优化。
还不够快?
考虑塔尖缩点,一个强联通分量缩成一个点之后只要经过这个点,它里面的点都能被经过,所以记录size即可。
好吧,典型的空间换时间……
代码时刻
暴力:
#include<bits/stdc++.h>
using namespace std;
struct rec
{
int nxt;
int to;
}e[4000000];
int head[2001],cnt;
bool vis[2001];
long long ans;
char ch[2001];
void add(register int x,register int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs(register int x)
{
vis[x]=1;
ans++;
for(register int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to])dfs(e[i].to);
}
int main()
{
int n;
scanf("%d",&n);
for(register int i=1;i<=n;i++)
{
scanf("%s",ch+1);
for(register int j=1;j<=n;j++)if(ch[j]=='1')add(i,j);
}
for(register int i=1;i<=n;i++)memset(vis,0,sizeof(vis)),dfs(i);
printf("%d",ans);
return 0;
}
//推荐使用register进行卡常,评测机稍卡都有可能过不了,然而我5分钟1A了……
bitset优化:
#include<bits/stdc++.h>
using namespace std;
char ch[2001];
bitset<2001> a[2001];//bitset
int ans;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",ch+1);
for(int j=1;j<=n;j++)
if(ch[j]=='1')a[i][j]=1;
a[i][i]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[j][i])a[j]|=a[i];//运用floyed思想
for(int i=1;i<=n;i++)ans+=a[i].count();//统计答案
cout<<ans<<endl;
return 0;
}
//我觉得代码好小巧,你觉得呢?
塔尖+bitset:
#include<bits/stdc++.h>
using namespace std;
struct rec
{
int nxt;
int to;
}e[4000000],wzc[4000000];
int n;
int head[2001],cnt;
int headw[2001],cntw;
long long ans;
char ch[2001];
int dfn[2001],low[2001],sta[2001],ins[2001],c[2001],size[2001],num,top,tot;
int que[2001],d[2001],lft=1,rht=1;
bitset<2001> a[2001];
void add(int x,int y)//旧图
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void add_w(int x,int y)//新图
{
wzc[++cntw].nxt=headw[x];
wzc[cntw].to=y;
headw[x]=cntw;
}
void tarjan(int x)//缩点
{
dfn[x]=low[x]=++num;
sta[++top]=x;
ins[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
if(!dfn[e[i].to])
{
tarjan(e[i].to);
low[x]=min(low[x],low[e[i].to]);
}
else if(ins[e[i].to])
low[x]=min(low[x],dfn[e[i].to]);
}
if(dfn[x]==low[x])
{
tot++;
int y;
do
{
y=sta[top--];
ins[y]=0;
c[y]=tot;
size[tot]++;
}while(x!=y);
}
}
void build()//建新图
{
for(int x=1;x<=n;x++)
for(int i=head[x];i;i=e[i].nxt)
if(c[x]!=c[e[i].to])
{
add_w(c[x],c[e[i].to]);
d[c[e[i].to]]++;
}
}
void _doudou()//统计答案
{
for(int i=1;i<=tot;i++)
if(!d[i])que[++rht]=i;
while(lft<=rht)
{
a[que[lft]][que[lft]]=1;
for(int i=headw[que[lft]];i;i=wzc[i].nxt)
{
a[wzc[i].to]|=a[que[lft]];
d[wzc[i].to]--;
if(!d[wzc[i].to])que[++rht]=wzc[i].to;
}
lft++;
}
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
if(a[i][j])ans+=size[i]*size[j];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",ch+1);
for(int j=1;j<=n;j++)if(ch[j]=='1')add(i,j);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
build();
_doudou();
printf("%d",ans);
return 0;
}
//比较恶心,考试的时候建议使用前两种做法,这种做法仅供参考和装逼……
rp++
[BZOJ2208]:[Jsoi2010]连通数(暴力 or bitset or 塔尖?)的更多相关文章
- bzoj2208 [Jsoi2010]连通数(scc+bitset)
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1879 Solved: 778[Submit][Status ...
- [BZOJ2208][Jsoi2010]连通数 暴力枚举
Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图 ...
- BZOJ2208 [Jsoi2010]连通数[缩点/Floyd传递闭包+bitset优化]
显然并不能直接dfs,因为$m$会非常大,复杂度就是$O(mn)$: 这题有三种做法,都用到了bitset的优化.第二种算是一个意外的收获,之前没想到竟然还有这种神仙操作.. 方法一:缩点+DAG上b ...
- [bzoj2208][Jsoi2010]连通数_bitset_传递闭包floyd
连通数 bzoj-2208 Jsoi-2010 题目大意:给定一个n个节点的有向图,问每个节点可以到达的点的个数和. 注释:$1\le n\le 2000$. 想法:网上有好多tarjan+拓扑序dp ...
- BZOJ2208: [Jsoi2010]连通数(tarjan bitset floyd)
题意 题目链接 Sol 数据水的一批,\(O(n^3)\)暴力可过 实际上只要bitset优化一下floyd复杂度就是对的了(\(O(\frac{n^3}{32})\)) 还可以缩点之后bitset维 ...
- 2018.09.11 bzoj2208: [Jsoi2010]连通数(bitset+floyd)
传送门 听说正解是缩点+dfs? 直接bitset优化floyd传递闭包就行了.(尽管时间复杂度是假的O(n3/32)" role="presentation" styl ...
- BZOJ2008 JSOI2010连通数(floyd+bitset)
一直不明白为什么要用floyd求传递闭包,直接搜不是更快嘛……不过其实可以用bitset优化,方法也比较显然.bitset是真的神奇啊,好多01状态且转移相似的东西都可以用这个优化一下. #inclu ...
- BZOJ2208: [Jsoi2010]连通数
tarjan缩点后拓扑排序,每一个点用一个bitset记录哪些点能到达它. PS:数据太水,暴力能过. #include<bits/stdc++.h> using namespace st ...
- BZOJ2208:[JSOI2010]连通数(DFS)
Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图 ...
随机推荐
- Flink的时间类型和watermark机制
一FlinkTime类型 有3类时间,分别是数据本身的产生时间.进入Flink系统的时间和被处理的时间,在Flink系统中的数据可以有三种时间属性: Event Time 是每条数据在其生产设备上发生 ...
- 无障碍开发(六)之ARIA在HTML中的使用规则
ARIA使用规则一 如果你使用的元素( HTML5 )具有语义化,应该使用这些元素,而不应该重新定义一个添加ARIA的角色.状态或属性的元素. 浏览器的语义化标签已经默认隐含ARIA语义,像nav,a ...
- pthread 笔记
1.创建线程 res = pthread_create(&a_thread, NULL, thread_function1, NULL); if (res != 0) { perror(&qu ...
- springcloud(十二)-springcloud-config统一管理微服务配置
1.为什么要统一管理微服务配置 对于传统的单体应用,常使用配置文件管理所有配置.例如一个SpringBoot开发的单体应用,可将配置内容放在application.yml文件中.如果需要切换环境,可设 ...
- kbmMW 5.09测试报告(1)-Scheduler
这个版本除了增加新的SmartBinding功能,同时提供了大量的功能更新以及bug修正.其中,SmartBinding的介绍,xalion已经第一时间写了初识kbmmw 中的smartbind功能, ...
- Java学习笔记【十三、多线程编程】
概念 Java 给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径. 多线程是多任务的一种特别的形式,但多线 ...
- C++ 批量打开写入文件
用到了C++17的filesystem 库 说明:这个函数主要是用来处理日志中不同Thread的日志,主要目的是将不同Thread的日志写到不同的文件中 int GetThreadTime(const ...
- ubantu32位 linux下hexedit的下载安装
Hexedit软件介绍: hexedit是一个开源的完全免费的命令行软件,可用于在任何GNU / Linux操作系统下以十六进制和ASCII(美国信息交换标准代码)格式查看和编辑文件. 下载: 在so ...
- Hive权限管理(十)
Hive权限管理 1.hive授权模型介绍 (1)Storage Based Authorization in the Metastore Server 基于存储的授权 - 可以对Metastore中 ...
- Kaggle_泰坦尼克乘客存活预测
转载 逻辑回归应用之Kaggle泰坦尼克之灾 此转载只为保存!!! ————————————————版权声明:本文为CSDN博主「寒小阳」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附 ...