bzoj2208
首先有向图的题目不难想到先tarjan缩点
一个强连通分量中的点的连通数显然是相等;
据说这样直接dfs就可以过了,但显然不够精益求精
万一给定的是一个完全的DAG图怎么办,dfs铁定超时;
首先想,dfs进行了很多不必要的操作,比如说i--->j
那么j的连通数一定也是i的连通数,但我们做dfs是需要做两遍的,降低了效率
那么为了提高效率,我们希望支持一个这样的操作
记录下每个点所能到的点,并且能快速的合并;
不由的想到位运算,但是最多只有30位,而实际有2000个点怎么办?
那我们就维护最多70个数,每个数表示到达情况
dp[k,i]为一个表示连通状况的数
第i个数的二进制上第j个位置(位置从右往左,0~30) 代表点k能否到达点(i-1)*30+j+1 (1代表可到达,0代表不可)
然后从出度为0的点不断dp即可;
具体见程序,表达不清,时间复杂度大约是O(nm/30) 还是非常优秀的
type link=^node;
node=record
po:longint;
next:link;
end; var edge,way:array[..] of link;
v,f:array[..] of boolean;
be,count,dfn,low,st:array[..] of longint;
dp:array[..,..] of longint;
ans,s,state,h,t,l,x,y,i,j,n,m:longint;
ch:ansistring;
p:link; function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end; procedure add(y:longint;var q:link);
var p:link;
begin
new(p);
p^.po:=y;
p^.next:=q;
q:=p;
end; procedure tarjan(x:longint);
var y:longint;
p:link;
begin
p:=edge[x];
v[x]:=true;
f[x]:=true;
inc(h);
dfn[x]:=h;
low[x]:=h;
inc(t);
st[t]:=x;
while p<>nil do
begin
y:=p^.po;
if not v[y] then
begin
tarjan(y);
low[x]:=min(low[x],low[y]);
end
else if f[y] then
low[x]:=min(low[x],low[y]);
p:=p^.next;
end;
if low[x]=dfn[x] then
begin
inc(s);
while st[t+]<>x do
begin
y:=st[t];
f[y]:=false;
be[y]:=s;
inc(count[s]);
dec(t);
end;
end;
end; procedure merge(x,y:longint); //合并点的连通情况
var i,j:longint;
begin
for i:= to state do
dp[x,i]:=dp[x,i] or dp[y,i];
end; function get(x:longint):longint;
var i,j,r:longint;
begin
get:=;
for i:= to state do //穷举每个数
for j:= to do //穷举二进制的每一位
begin
r:= shl j; //位运算的技巧
if r>dp[x,i] then break;
if (dp[x,i] and r)<> then
get:=get+count[(i-)*+j+];
end;
end; begin
readln(n);
for i:= to n do
begin
readln(ch);
for j:= to n do
begin
x:=ord(ch[j])-;
if x<> then add(j,edge[i]);
end;
end;
for i:= to n do
if not v[i] then
begin
h:=;
t:=;
tarjan(i);
end; fillchar(dfn,sizeof(dfn),);
for i:= to n do
begin
p:=edge[i];
while p<>nil do
begin
y:=p^.po;
if be[y]<>be[i] then
begin
inc(dfn[be[i]]); //计算出度
add(be[i],way[be[y]]); //缩点后记录点be[y]被那些点指向
end;
p:=p^.next;
end;
end;
fillchar(v,sizeof(v),false);
t:=;
for i:= to s do
edge[i]:=nil;
for i:= to s do
begin
p:=way[i];
while p<>nil do
begin
x:=p^.po;
add(i,edge[x]); //记录点i指向那些点
p:=p^.next;
end;
x:=(i-) div +;
y:=(i-) mod ;
dp[i,x]:= shl y; //每个点对自己都是可达的
end;
for i:= to s do
if dfn[i]= then //从出度为0的点开始dp
begin
inc(t);
st[t]:=i;
end; state:=s div +;
l:=;
while l<=t do
begin
inc(l);
x:=st[l];
p:=edge[x];
while p<>nil do
begin
y:=p^.po;
merge(x,y); //每个x指向的点的连通数一定也是x的连通数,合并
p:=p^.next;
end;
ans:=ans+count[x]*get(x); //计算连通数
p:=way[x];
while p<>nil do //类似拓扑排序,删除点x,寻找新的出度为0的点
begin
y:=p^.po;
dec(dfn[y]);
if dfn[y]= then
begin
inc(t);
st[t]:=y;
end;
p:=p^.next;
end;
end;
writeln(ans);
end.
bzoj2208的更多相关文章
- 【BZOJ2208】[JSOI2010]连通数(Tarjan)
[BZOJ2208][JSOI2010]连通数(Tarjan) 题面 BZOJ 洛谷 题解 先吐槽辣鸡洛谷数据,我写了个\(O(nm)\)的都过了. #include<iostream> ...
- 【BZOJ2208】[Jsoi2010]连通数 DFS
[BZOJ2208][Jsoi2010]连通数 Description Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每行N个字符.第i行第j列的1表示顶点i到j有边,0则表示 ...
- [bzoj2208][Jsoi2010]连通数_bitset_传递闭包floyd
连通数 bzoj-2208 Jsoi-2010 题目大意:给定一个n个节点的有向图,问每个节点可以到达的点的个数和. 注释:$1\le n\le 2000$. 想法:网上有好多tarjan+拓扑序dp ...
- BZOJ2208: [Jsoi2010]连通数
tarjan缩点后拓扑排序,每一个点用一个bitset记录哪些点能到达它. PS:数据太水,暴力能过. #include<bits/stdc++.h> using namespace st ...
- bzoj2208:[Jsoi2010]连通数
http://blog.csdn.net/u013598409/article/details/47037499 里面似乎有生成数据的... //我本来的想法是tarjan缩点之后然后将图遍历一遍就可 ...
- bzoj2208 [Jsoi2010]连通数(scc+bitset)
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1879 Solved: 778[Submit][Status ...
- 【BZOJ2208】【JSOI2010】连通数 传递闭包
题目描述 定义一个图的连通度为图中可达顶点对的数目.给你一个\(n\)个点的有向图,问你这个图的连通度. \(n\leq 2000,m\leq n^2\) 题解 一个很简单的做法就是传递闭包:像flo ...
- bzoj2208 连通数(bitset优化传递闭包)
题目链接 思路 floyd求一下传递闭包,然后统计每个点可以到达的点数. 会tle,用bitset优化一下.将floyd的最后一层枚举变成bitset. 代码 /* * @Author: wxyww ...
- BZOJ2208: [Jsoi2010]连通数(tarjan bitset floyd)
题意 题目链接 Sol 数据水的一批,\(O(n^3)\)暴力可过 实际上只要bitset优化一下floyd复杂度就是对的了(\(O(\frac{n^3}{32})\)) 还可以缩点之后bitset维 ...
随机推荐
- ZOJ 2392 The Counting Problem(模拟)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1368 题目大意:计算从S到T中所有的数,其中0,1,2,3,4,5, ...
- linux修改时间 时区
查看时区:date -R 修改时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 二.时间 1.查看时间和日期 date 2.设置时间和日期 ...
- Putty终端 模拟 远程登录 虚拟机Linux
1.虚拟机设置 虚拟机设置->网络适配器->选择Host-only:与主机共享一个私有网络 桥接.NAT.Host-only三种网络模式的说明: (1)桥接:表示在局域网内是一台真实的系统 ...
- 《APUE》第四章笔记(3)
文件系统 首先我们应该知道一个磁盘可以划分为多个分区,而每个分区就可以包含一个文件系统.UNIX的文件系统是这样的: 而我们主要关心的是i节点和数据块.i节点是固定长度的记录项,它包含有关文件的大部分 ...
- Linux下Qt环境的搭建
之前一直使用Ubuntu软件中心中的Qt4开发Qt的应用程序,现在转到Linux下来做Qt5开发,但是必须从Qt官网上面下载对应的安装包,配置起来相对麻烦一些,这里介绍整个开发流程. 首先,在官网上面 ...
- 【转】怎样将DataGridView中绑定的表的列名改成中文
在DataGridView设置数据源绑定后,设置DataGridView的属性HeaderText就可以了.代码参考: dataGridView.Columns[filedName].HeaderTe ...
- iis7以上版本权限控制
IIS7.5中(仅win7,win2008 SP2,win2008 R2支持),应用程序池的运行帐号,除了指定为LocalService,LocalSystem,NetWorkService这三种基本 ...
- Linux和Windows下查看环境变量方法对比
摘自:Linux和Windows下查看环境变量方法对比 一.查看所有环境变量的名称和值 Linux下:export Windows下:set 二.根据名称查该环境变量的值 Linux下:echo $环 ...
- .net entity framework 泛型 更新与增加记录
static public bool SaveOrUpdate<T>(T entity) where T: class { bool result = false; using (wech ...
- 关于xcode6打包以及上线前企业部署测试的说明 --转自张诚教授微博
xcode6如何打包 首先clean然后点击归档 点击打包之后保存 点选第一个以后检查相关证书签名 那么我们开发完以后,在上线前如何给别人测试 有2种方法 1.使用299美金的企业开发者账号搭建企业部 ...