[JSOI2010]连通数 (dfs或tarjan或bitset)+bitset学习
题目描述
输入格式
输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。
输出格式
输出一行一个整数,表示该图的连通数。
样例
样例输入
3
010
001
100
样例输出
9
数据范围与提示
对于100%的数据,N不超过2000。
solution:
这道题给出三种算法:
DFS:
这道题搜索可以过
用vecter建边,若有一条由i指向j的边,那么把j压到i的vector中(这种建边方法好像比前向星快)
建立bool数组vis,vis[i][j]=1表示已经访问过由i指向j的边
我们对于每一个点进行dfs,其中dfs(i,j)表示以i为起点开始搜索,当前搜到了j点,依次向下dfs并统计答案
由于这里的vis存的是边的信息,所以不用考虑环。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define MAXN 2005
using namespace std;
int n,ans[MAXN],res=;
char ch[MAXN][MAXN];
vector<int>mapa[MAXN];
bool vis[MAXN][MAXN];//vis[i][j]表示是否访问过由i向j的边
void dfs(int st,int now){//st:起点,now:当前节点
ans[st]++;
vis[st][now]=;
int m=mapa[now].size();
for(int i=;i<m;i++){
if(!vis[st][mapa[now][i]])
dfs(st,mapa[now][i]);
}
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",ch[i]+);
for(int j=;j<=n;j++){
if(ch[i][j]=='')
mapa[i].push_back(j);
//cout<<ch[i][j];
}
//cout<<endl;
}
for(int i=;i<=n;i++)
dfs(i,i),res+=ans[i];
printf("%d\n",res);
return ;
}
代码在这里!
TARJAN:
缩点再建图,这是最主流的方法,不再赘述:
#include<bits/stdc++.h>
using namespace std;
bitset<> t[];
int n,ans=,e[],in[];char s[];
int dfn[],low[],st[],num=,top=,cnt=;
bool ins[];
int tot=,first[],len[];
vector<int> edge[],scc[];
struct node{int v,next;}eg[];
inline void add(int x,int y)
{
eg[++tot].v=y;
eg[tot].next=first[x];
first[x]=tot;
}
inline void tarjan(int x)
{
dfn[x]=low[x]=++num;
st[++top]=x;ins[x]=;
for(register int i=;i<edge[x].size();i++)
{
int to=edge[x][i];
if(!dfn[to])
{
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(ins[to])
low[x]=min(low[x],dfn[to]);
}
if(dfn[x]==low[x])
{
cnt++;int y;
do{
y=st[top--],ins[y]=;
t[cnt][y]=,++len[cnt];
e[y]=cnt,scc[cnt].push_back(y);
}while(x!=y);
}
}
int main()
{
scanf("%d",&n);
for(register int i=;i<=n;i++)
{
scanf("%s",s+);
for(register int j=;j<=n;j++)
if(s[j]=='')edge[i].push_back(j);
}
for(register int i=;i<=n;i++)
if(!dfn[i])tarjan(i);
for(register int i=;i<=n;i++)
for(register int j=;j<edge[i].size();j++)
{
int to=edge[i][j];
if(e[i]==e[to])continue;
add(e[i],e[to]);
in[e[to]]++;
}
queue<int> q;
for(register int i=;i<=cnt;i++)
if(!in[i])q.push(i);
while(!q.empty())
{
int x=q.front();q.pop();
for(register int i=first[x];i;i=eg[i].next)
{
int to=eg[i].v;
t[to]|=t[x];
in[to]--;
if(!in[to])q.push(to);
}
}
for(register int i=;i<=n;i++)
ans+=t[i].count()*len[i];
printf("%d",ans);
}
BITSET:
我们借助c++STL解决问题,对于每个点建一个bitset;
bitset可以理解为一个加长的二进制数,普通二进制数的位运算bitset都能做,(&|~^>><<)
C++的 bitset 在 bitset 头文件中,它是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间。
定义:bitset<n>b//长度为n,名称为b的一个bitset
相关函数:
b.size() 返回大小(位数)
b.count() 返回1的个数
b.any() 返回是否有1
b.none() 返回是否没有1
b.set() 全都变成1
b.set(p) 将第p + 1位变成1
b.set(p, x) 将第p + 1位变成x
b.reset() 全都变成0
b.reset(p) 将第p + 1位变成0
b.flip() 全都取反
b.flip(p) 将第p + 1位取反
b.to_ulong() 返回它转换为unsigned long的结果,如果超出范围则报错
b.to_ullong() 返回它转换为unsigned long long的结果,如果超出范围则报错
b.to_string() 返回它转换为string的结果
至于它的时间复杂度,和电脑本身有关,一般来说是使复杂度/32
一段关于bitset的代码:
#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>
const int N=10;
std::bitset<N> a,b;//如果定义数组写成bitset<N> a[M];
int main(){
puts("stage 0");
std::cout<<a<<std::endl;
std::cout<<b<<std::endl;
a[1]=1;
b[0]=1;
puts("stage 1");
std::cout<<a[1]<<std::endl;
std::cout<<b[0]<<std::endl;
std::cout<<a<<std::endl;
std::cout<<b<<std::endl;
a=a|b;//等效于a|=b
puts("stage 2");
std::cout<<a<<std::endl;
a=a<<3;//等效于a<<=3
puts("stage 3");
std::cout<<a<<std::endl;
a=a>>3;//等效于a>>=3
puts("stage 4");
std::cout<<a<<std::endl;
a=a^b;//等效于a^=b
puts("stage 5");
std::cout<<a<<std::endl;
a=a&b;//等效于a&=b;
puts("stage 6");
std::cout<<a<<std::endl;
a.set();
puts("stage 7");
std::cout<<a<<std::endl;
a.reset();
puts("stage 8");
std::cout<<a<<std::endl;
a=~b;
puts("stage 9");
std::cout<<a<<std::endl;
std::cout<<b<<std::endl;
a[2]=0,a[5]=0;
puts("stage 10");
std::cout<<a<<std::endl;
std::cout<<a.count()<<" "<<a.size()<<std::endl;
b=a;
puts("stage 11");
std::cout<<b<<std::endl;
a=5;
puts("stage 12");
std::cout<<a<<std::endl;
return 0;
}
//时间复杂度,整体操作都是长度/32(64位机器除64),单个操作(操作单个位)是O(1)的
//空间复杂度,8位1字节,具体计算规则为在32位机器上Size = 4 * ((N + 31) / 32)在64位机器上Size = 8* ((N + 63) / 64)
bitset<> foo (""); string s = foo.to_string(); //将bitset转换成string类型
unsigned long a = foo.to_ulong(); //将bitset转换成unsigned long类型
unsigned long long b = foo.to_ullong(); //将bitset转换成unsigned long long类型 cout << s << endl; //
cout << a << endl; //
cout << b << endl; //
bitset<> foo (""); cout << foo.flip() << endl; //10011111 (flip函数传参数时,用于将参数位取反,本行代码将foo下标2处"反转",即0变1,1变0
cout << foo.flip() << endl; //01100000 (flip函数不指定参数时,将bitset每一位全部取反 cout << foo.set() << endl; //11111111 (set函数不指定参数时,将bitset的每一位全部置为1
cout << foo.set(,) << endl; //11110111 (set函数指定两位参数时,将第一参数位的元素置为第二参数的值,本行对foo的操作相当于foo[3]=0
cout << foo.set() << endl; //11111111 (set函数只有一个参数时,将参数下标处置为1 cout << foo.reset() << endl; //11101111 (reset函数传一个参数时将参数下标处置为0
cout << foo.reset() << endl; //00000000 (reset函数不传参数时将bitset的每一位全部置为0
以上三段代码均来自大佬博客和题解(%%)
了解了bitset,我们要用它来解题了
b[i]表示一种状态,若b[i][j]=1,则表示有一条由i向j连的边(i也要和自己连边)
若i能到j,那么i也能到j所能到的点,那么直接b[i]|b[j]即能把状态转移:
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
if(bit[i][j]) bit[i]|=bit[j];
这里一定是要j在外层,i在内层,原因博主还没有想通,有理解的欢迎在评论区留言
最后我们用bitset函数中的count()统计每个bitset中1的个数,然后输出答案
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<bitset>
#define MAXN 2005
using namespace std;
int n,ans=0;
bitset<MAXN>bit[MAXN];
char st[MAXN];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",st+1);
for(int j=1;j<=n;j++)
if(st[j]=='1')
bit[i][j]=1;
bit[i][i]=1;
}
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++)
if(bit[i][j]) bit[i]|=bit[j];
for(int i=1;i<=n;i++)
ans+=bit[i].count();
printf("%d\n",ans);
return 0;
}
[JSOI2010]连通数 (dfs或tarjan或bitset)+bitset学习的更多相关文章
- 【BZOJ2208】[Jsoi2010]连通数 DFS
[BZOJ2208][Jsoi2010]连通数 Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示 ...
- BZOJ 2208: [Jsoi2010]连通数( DFS )
n只有2000,直接DFS就可以过了... -------------------------------------------------------------------------- #in ...
- BZOJ2208:[JSOI2010]连通数(DFS)
Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示无边. Output 输出一行一个整数,表示该图 ...
- BZOJ 2208: [Jsoi2010]连通数 tarjan bitset
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- bzoj2208 [Jsoi2010]连通数(scc+bitset)
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1879 Solved: 778[Submit][Status ...
- BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset
BZOJ_2208_[Jsoi2010]连通数_强连通分量+拓扑排序+手写bitset Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i ...
- 【BZOJ2208】[JSOI2010]连通数(Tarjan)
[BZOJ2208][JSOI2010]连通数(Tarjan) 题面 BZOJ 洛谷 题解 先吐槽辣鸡洛谷数据,我写了个\(O(nm)\)的都过了. #include<iostream> ...
- bzoj2208:[Jsoi2010]连通数
http://blog.csdn.net/u013598409/article/details/47037499 里面似乎有生成数据的... //我本来的想法是tarjan缩点之后然后将图遍历一遍就可 ...
- 2208: [Jsoi2010]连通数
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1371 Solved: 557[Submit][Status ...
随机推荐
- csp-s模拟100,101T1,T2题解
题面:https://www.cnblogs.com/Juve/articles/11799325.html 我太蒻了只会T1T2 组合: 欧拉路板子?不会呀... 然后打了个优化,防止暴栈 #inc ...
- csps模拟8990部分题解
题面: 666: 重点在题意转化:每个数可以乘k,代价为k,可以减一,代价为1, 所以跑最短路即可 #include<iostream> #include<cstdio> #i ...
- 概率dp——逆推期望+循环迭代zoj3329
首先要推出dp[i]的期望方程,会发现每一项都和dp[0]相关, 那我们将dp[i]设为和dp[0]有关的式子dp[i]=a[i]*dp[0]+b[i],然后再回代到原来的期望方程里 然后进行整理,可 ...
- 关于maven工程将model删除重建之后变为灰色的问题的解决
问题描述: IDEA中的maven工程中有时候将model或者子model建错,删除之后,子模块在maven在侧栏的maven projects中是灰色的,而且是并没有依赖父工程 在网上搜了搜解决办法 ...
- js 盒子模型与盒子偏移量
js 盒子模型: 通过js中提供的一系列属性和方法获取页面中元素的样式信息值. 一.client系类—>只读属性不可设置 (当前元素的私有属性,和内容溢出没关系,如果给容器设置了高度,就采用设置 ...
- exit与return的区别
===========================PHP的解释=========================================================== return ...
- 设置IDEA自动提示补全代码,关于idea自动补全的详细设置。
在IDEA中,默认的代码自动提示不够智能,现在配置成更加智能的方式. File-Settings-Editor-General-Code Completion中 把最上面的大小写敏感度改成none,下 ...
- mybatis中处理结果集映射
单行结果集映射: 接口中方法返回值定义为Map类型,sql语句的resultType属性设置为map即可.这种情况默认把列名作为key,列中的值作为value. 也就是说用map<Strirng ...
- 移植 inetd
inetd 的选择及获取 Busybox1.1.3 提供了 inetd 支持.如果读者使用的是较低版本的不提供 inetd 的 Busybox,那么可以考虑使 用 netkit 套件来提供网络服务.强 ...
- rem适配手机
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...