Luogu P4306 JSOI2010 连通数
tarjan有向图缩点的基础应用。把原图中某点的连通数转化为反向图中”能够到达某点的个数“。缩点后,每个新点的贡献等于
原dcc大小 * f[i]
其中f[i]表示(包括该点自身)通向该点的点的个数。设u点为v的入度,满足转移方程:
所以我们按照拓扑序dp求解即可。f[i]的初值设为该分量的节点数。
这个题引出一个很重要的想法:如何避免两个强连通分量缩点时连有重边?对于2000的数据范围,一个二维布尔数组完全可以承受,但显然有更普适的优秀做法,这就是Hash。去重边实际上是二元组的判重问题,我们只需要一个合适的“进位”技术,就可以保证任意两个二元组所映射的键值是绝不相同的。如果key值太大,就要套用Hash表解决了。
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <queue>
- #include <cctype>
- #define maxn 2010
- using namespace std;
- template <typename T>
- void read(T &x) {
- x = 0;
- char ch = getchar();
- while (!isdigit(ch))
- ch = getchar();
- while (isdigit(ch))
- x = x * 10 + (ch ^ 48),
- ch = getchar();
- return;
- }
- struct E {
- int to, nxt;
- } edge[maxn * maxn], edge2[maxn * maxn];
- int n, head[maxn], top, head2[maxn], top2;
- inline void insert(int u, int v) {
- edge[++top] = (E) {v, head[u]};
- head[u] = top;
- }
- inline void insert2(int u, int v) {
- edge2[++top2] = (E) {v, head2[u]};
- head2[u] = top2;
- }
- int dfn[maxn], low[maxn], timer,
- sta[maxn], stp,
- c[maxn], cnt,
- w[maxn];
- bool ins[maxn];
- void tarjan_dfs(int u) {
- dfn[u] = low[u] = ++timer;
- sta[++stp] = u, ins[u] = true;
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (!dfn[v])
- tarjan_dfs(v), low[u] = min(low[u], low[v]);
- else if (ins[v])
- low[u] = min(low[u], dfn[v]);
- }
- if (dfn[u] == low[u]) {
- ++cnt;
- int x;
- do {
- x = sta[stp--];
- ins[x] = false;
- c[x] = cnt;
- ++w[cnt];
- } while (x != u);
- }
- }
- void tarjan() {
- for (int i = 1; i <= n; ++i)
- if (!dfn[i]) tarjan_dfs(i);
- }
- namespace Hash_table {
- // const int Size(23333309), step = 7;//空间足够,不用取模
- bool tb[4004001];
- inline int H (int u, int v) {
- return u * 2001 + v;
- }
- bool Hash(int u, int v) {
- int key = H(u, v);
- if (tb[key]) return false;
- tb[key] = true;
- return true;
- }
- } using namespace Hash_table;
- int ind[maxn];
- //bool done[maxn][maxn];//Hash更为优秀
- void build() {
- for (int u = 1; u <= n; ++u)
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (c[u] != c[v] && Hash(c[u], c[v])) {
- insert2(c[u], c[v]);
- ++ind[c[v]];
- }
- }
- }
- long long sum = 0;
- long long f[maxn];
- queue<int> que;
- void dp() {
- for (int i = 1; i <= cnt; ++i) {
- f[i] = w[i];
- if (!ind[i]) {
- sum += w[i] * w[i];
- que.push(i);
- }
- }
- while (!que.empty()) {
- int u = que.front(); que.pop();
- for (int i = head2[u]; i; i = edge2[i].nxt) {
- int v = edge2[i].to;
- f[v] += f[u];
- --ind[v];
- if (!ind[v]) {
- sum += w[v] * f[v];
- que.push(v);
- }
- }
- }
- }
- int main() {
- read(n);
- for (int u = 1; u <= n; ++u)
- for (int v = 1; v <= n; ++v) {
- char ch = getchar();
- while (!isdigit(ch)) ch = getchar();
- if (ch == '1') insert(v, u);//反向存图
- }
- tarjan();
- build();
- dp();
- printf("%lld", sum);
- return 0;
- }
Luogu P4306 JSOI2010 连通数的更多相关文章
- Luogu P4306 [JSOI2010]连通数 传递闭包
正解其实是\(Tarjan\) + \(拓扑拓扑\),但是却可以被\(O(N^3 / 32)\)复杂度的传递闭包水过去.心疼一下写拓扑的小可爱们. 学到一个\(bitset\)优化布尔图的骚操作,直接 ...
- P4306 [JSOI2010]连通数
思路 要求求每个点能到达的点数就是传递闭包 然后n^3Floyd可做,但是n=2000,然后bitset压位 复杂度\(O(\frac{n^3}{32})\),能过 代码 #include <c ...
- BZOJ 2208: [Jsoi2010]连通数 tarjan bitset
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- 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 ...
- BZOJ 2208: [Jsoi2010]连通数( DFS )
n只有2000,直接DFS就可以过了... -------------------------------------------------------------------------- #in ...
- 2208: [Jsoi2010]连通数
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1371 Solved: 557[Submit][Status ...
- bzoj 2208 [Jsoi2010]连通数
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 输入数据第一行是图顶点的数量,一个正整数N ...
- 【BZOJ2208】[JSOI2010]连通数(Tarjan)
[BZOJ2208][JSOI2010]连通数(Tarjan) 题面 BZOJ 洛谷 题解 先吐槽辣鸡洛谷数据,我写了个\(O(nm)\)的都过了. #include<iostream> ...
随机推荐
- git每次提交代码都要设置账号密码的问题
git config --global credential.helper store 待下一次提交代码的时候,输入了正确的用户名和密码,之后 就不需要输入用户名密码
- mysql 事务的日志
事务的日志 1.redo log redo:"重做",记录的是,内存数据页的变化过程 1)作用 在事务ACID过程中,实现的是 "D" 持久化的作用. 2)工作 ...
- Github优质库分享-01算法小抄 基于LeetCode
Github 优质库分享-01 算法小抄 该库总共 60 多篇原创文章,都是基于 LeetCode 的题目,涵盖了所有题型和技巧,而且一定要做到举一反三,通俗易懂,绝不是简单的代码堆砌. 目前 sta ...
- python框架Django中的MTV架构
MTV架构 关注公众号"轻松学编程"了解更多. 通过V对M和T进行连接,用户通过T(界面)对服务器进行访问(发送请求),T把请求传给V(调度),V调用M(数据模型)获取数据,把 ...
- React中useLayoutEffect和useEffect的区别
重点: 1.二者函数签名相同,调用方式是一致的 2. 怎么简单进行选择: 无脑选择useEffect,除非运行效果和你预期的不一致再试试useLayoutEffect 区别详解:useEffect是异 ...
- final,static,this,super 关键字总结
一.final 关键字 final关键字主要用在三个地方:变量.方法.类. 1.对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改:如果是引用类型的变量,则在对其初始 ...
- ASP.NET Core框架揭秘[博文汇总-持续更新]
第1部分 跨平台开发体验 1 跨平台开发体验 001 跨平台开发体验: Windows [上篇] 002 跨平台开发体验: Windows [中篇] 003 跨平台开发体 ...
- 不断要求用户输入学生姓名,输入q结束.
while (true) { Console.WriteLine("请输入学生姓名"); string a = Console.ReadLine(); if (a == " ...
- keras中的early stopping
目的:防止过拟合 # early stoppping from keras.callbacks import EarlyStopping early_stopping = EarlyStopping( ...
- C# Span 源码解读和应用实践
一:背景 1. 讲故事 这两天工作上太忙没有及时持续的文章产出,和大家说声抱歉,前几天群里一个朋友在问什么时候可以产出 Span 的下一篇,哈哈,这就来啦!读过上一篇的朋友应该都知道 Span 统一了 ...