[BZOJ2208][Jsoi2010]连通数(dfs||tarjan+拓扑序+dp)
2016-11-01 23:03
465 查看
题目描述
传送门题解
看范围很小,O(n2)暴力就可以做啊= =BZOJ上跑到10s+的比比皆是,事实证明很多人都这样水掉了,而且这样的暴力是卡不掉的。其实还有一种更高级的做法,就是tarjan+拓扑序+dp。首先将整个图缩点,同一个强连通分量中的点两两互达,所以答案统计为size2i。对于不在一个强连通分量里的点,反向连边然后按照拓扑序dp,状态表示为f(i,j)当前到第i个点且与i相连的点状态为j的方案数。也就是说j其实是个状压,用bitset高效实现。
但是其实这种实现在极限情况下也是O(n2)的,因为每一个点都可能单独成为一个分量
代码
#include<iostream> #include<cstring> #include<cstdio> #include<bitset> #include<queue> using namespace std; #define N 2005 int n,scc,dfs_clock; bool vis ,has ; int tot,point ,nxt[N*N],v[N*N]; int tott,pointt ,nxtt[N*N],vt[N*N]; int size ,dfn ,low ,stack ,tmp=0,belong ,in ,sum ; int ans; char s ; queue <int> q; bitset<N>f ; void add(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; } void addt(int x,int y) { ++tott; nxtt[tott]=pointt[x]; pointt[x]=tott; vt[tott]=y; } void tarjan(int x) { dfn[x]=low[x]=++dfs_clock;vis[x]=true;stack[++tmp]=x; for (int i=point[x];i;i=nxt[i]) if (!dfn[v[i]]) { tarjan(v[i]); low[x]=min(low[x],low[v[i]]); } else if (vis[v[i]]) low[x]=min(low[x],dfn[v[i]]); if (low[x]==dfn[x]) { ++scc;int now=0; while (now!=x) { now=stack[tmp--]; vis[now]=false; belong[now]=scc; size[scc]++; } } } void rebuild() { for (int i=1;i<=n;++i) for (int j=point[i];j;j=nxt[j]) if (belong[i]!=belong[v[j]]&&!has[belong[v[j]]][belong[i]]) { addt(belong[v[j]],belong[i]);in[belong[i]]++; has[belong[v[j]]][belong[i]]=true; } } void topo() { for (int i=1;i<=scc;++i) f[i][i]=1; for (int i=1;i<=scc;++i) if (!in[i]) q.push(i); while (!q.empty()) { int now=q.front();q.pop(); for (int i=pointt[now];i;i=nxtt[i]) { f[vt[i]]|=f[now]; --in[vt[i]]; if (!in[vt[i]]) q.push(vt[i]); } } for (int i=1;i<=scc;++i) for (int j=1;j<=scc;++j) if (f[i][j]) ans+=size[i]*size[j]; } int main() { scanf("%d\n",&n); for (int i=1;i<=n;++i) { gets(s); for (int j=1;j<=n;++j) if (s[j-1]=='1') add(i,j); } for (int i=1;i<=n;++i) if (!dfn[i]) tarjan(i); rebuild(); topo(); printf("%d\n",ans); }
总结
①tarjan相关的算法在有向图连通性方面还是非常有用的,要多想想。相关文章推荐
- BZOJ 2208 [Jsoi2010]连通数 tarjan缩点+bitset优化DP
- [BZOJ2208][Jsoi2010]连通数(tarjan+topdp)
- bzoj 2208: [Jsoi2010]连通数 (dfs|tarjan+bitset+拓扑序)
- BZOJ 2208 JSOI2010 连通数 Tarjan+拓扑排序
- BZOJ.2208.[JSOI2010]连通数(bitset Tarjan 拓扑)
- 【BZOJ2208】[Jsoi2010]连通数【BFS/DFS】【SCC】
- 【BZOJ2208】[Jsoi2010]连通数 DFS
- Dfs【p4306(bzoj 2208)】 [JSOI2010]连通数
- BZOJ 2208 JSOI 2010 连通数 Tarjan+bitset
- 【bzoj 2208】[Jsoi2010]连通数(dfs||Tarjan算法+拓扑序+dp)
- BZOJ 2208 [Jsoi2010]连通数 - Tarjan_SCC/Floyd+bitset优化
- BZOJ 2208: [Jsoi2010]连通数 tarjan bitset
- [tarjan+bitset]BZOJ 2208——[Jsoi2010]连通数
- BZOJ 2208: [Jsoi2010]连通数( DFS )
- BZOJ 2208 JSOI2010 连通数 Tarjan+拓扑排序
- bzoj 2208: [Jsoi2010]连通数【tarjan+拓扑+dp】
- [bzoj2208][Jsoi2010]连通数
- bzoj 2208: [Jsoi2010]连通数
- 【BZOJ2208】【JSOI2010】连通数 传递闭包
- bzoj2208 [Jsoi2010]连通数(scc+bitset)