bzoj2208 连通数 tarjan缩点&状压常数优化
2016-01-27 21:41
204 查看
这道题目还想并没有比O(N^3)更快的算法了。。除非从树的分治入手?
首先tarjan缩点(显然),然后就是个DAG。然后给缩成的强连通分量一个权值为它所含的点的个数,然后对于一个强连通分量该处的答案就是为该强连通分量的权值乘上这个强连通分量所能到达的点的个数(包括自身)。假设用f[i]表示强连通分量i能到达的点的集合,显然f[i]|={f[j]}当且仅当存在边(u,v)使u在强连通分量i中且v在j中,这个用记忆化轻松解决(递推也行)。
如果用二进制来表示,显然会爆(2^n),所以将这个二进制数转化为n/30个二进制数,这样每个数的大小就只有2^30了。由于求f数组时间复杂度为O((N+M)N/30)=O(N^3),但考虑到n最大为2000,而且还有1/30这样一个很小的常数,实际上运行速度还是很快的。
AC代码如下:
by lych
2016.1.27
首先tarjan缩点(显然),然后就是个DAG。然后给缩成的强连通分量一个权值为它所含的点的个数,然后对于一个强连通分量该处的答案就是为该强连通分量的权值乘上这个强连通分量所能到达的点的个数(包括自身)。假设用f[i]表示强连通分量i能到达的点的集合,显然f[i]|={f[j]}当且仅当存在边(u,v)使u在强连通分量i中且v在j中,这个用记忆化轻松解决(递推也行)。
如果用二进制来表示,显然会爆(2^n),所以将这个二进制数转化为n/30个二进制数,这样每个数的大小就只有2^30了。由于求f数组时间复杂度为O((N+M)N/30)=O(N^3),但考虑到n最大为2000,而且还有1/30这样一个很小的常数,实际上运行速度还是很快的。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #define N 2005 using namespace std; int n,m,cnt,tp,tmp,dfsclk,s ,pos ,low ,scc ,sum ,f [105]; int tot,fst ,pnt[N*N],nxt[N*N]; bool vis ,a ; void dfs(int x){ s[++tp]=x; pos[x]=low[x]=++dfsclk; int i; for (i=1; i<=n; i++) if (a[x][i]){ if (!pos[i]){ dfs(i); low[x]=min(low[x],low[i]); } else if (!scc[i]) low[x]=min(low[x],pos[i]); } if (low[x]==pos[x]){ for (sum[++cnt]=1; s[tp]!=x; tp--){ scc[s[tp]]=cnt; sum[cnt]++; } scc[x]=cnt; tp--; } } void add(int aa,int bb){ pnt[++tot]=bb; nxt[tot]=fst[aa]; fst[aa]=tot; } void solve(int x){ if (vis[x]) return; vis[x]=1; int p,i; for (p=fst[x]; p; p=nxt[p]){ int y=pnt[p]; solve(y); for (i=0; i<=m; i++) f[x][i]|=f[y][i]; } } int work(int x){ int ans=0; for (; x; x-=x&(-x)) ans++; return ans; } int main(){ scanf("%d",&n); int i,j; for (i=1; i<=n; i++){ char ch=getchar(); while (ch<'0' || ch>'1') ch=getchar(); for (j=1; j<=n; j++){ a[i][j]=(ch=='1'); ch=getchar(); } } for (i=1; i<=n; i++) if (!pos[i]) dfs(i); int ans=0; m=n/30; for (i=1; i<=n; i++) f[scc[i]][i/30]|=1<<(i%30); for (i=1; i<=n; i++) for (j=1; j<=n; j++) if (a[i][j] && scc[i]!=scc[j]) add(scc[i],scc[j]); for (i=1; i<=cnt; i++) if (!vis[i]){ solve(i); for (j=0; j<=m; j++) ans+=sum[i]*work(f[i][j]); } printf("%d\n",ans); return 0; }
by lych
2016.1.27
相关文章推荐
- 使用py2exe生成一个exe文件
- c#中的泛型
- CodeForces 593D Happy Tree Party
- spark学习4之集群上直接用scalac编译.scala出现的MissingRequirementError问题(已解决)
- zookeeper分布式配置测试
- 欢迎使用CSDN-markdown编辑器
- struts请求走向流程
- quartz---任务调度小试(多任务)
- Coursera课程《Python数据结构》中课件
- 加油站(贪心算法)
- Cassandra中Gossip具体实现方式
- LINK fatal error LNK1123 转换到COFF期间失败
- android sharedUserId 共享用户
- 网页自动加载进度条插件
- JS数组的forEach方法(兼容所有浏览器)
- 2.1.7 理解语句块、嵌套语句块和标签的作用范围
- cassandra 之 gossip实现
- javascript学习笔记之四
- Java
- Python入门学习笔记