scc

CF652E Pursuit For Aritifacts

谁说胖子不能爱 提交于 2020-04-04 23:05:13
题目传送门 这是一道很好的练习强联通的题目。 首先,从题中可以看到,题目的要求就是要我们求出从起点到终点是否可以经过flag = 1 的边。 由于是无向图,且要求很多,直接暴力dfs会很凌乱。 那么,我们就想到一个思路:能不能尽量把这张图缩小,标记转为点,最好成为一条一条链呢? tarjan的缩点!! 没错,对于一个环,可以想到,只要这个环中有一条边flag = 1,那么所有的点我们都可以通过falg = 1的边到达(因为这是环)。所以,不妨进行tarjan缩点,只要这个缩点中有一条边falg = 1,我们就把这个缩点打上tag。 再一想,经过缩点之后,原来十分凌乱的图就变成了一棵树。到达终点的路线也就只有固定一条了。这里我选择dfs。 思路大体就是这样,总时间复杂度O(M + N) 话不多说,具体细节操作标记在代码里面了。 #include<bits/stdc++.h> using namespace std; #define N 500010 #define isdigit(c) ((c)>='0'&&(c)<='9') inline int read(){ int x = 0,s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)

专题训练之强连通分量

北城余情 提交于 2020-04-04 04:23:18
tarjan模板 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=20010; 6 const int maxm=50010; 7 struct edge{ 8 int to,nxt; 9 }edge[maxm]; 10 int head[maxn],tot; 11 int low[maxn],dfn[maxn],stack[maxn],belong[maxn]; 12 int index,top; 13 int scc; 14 bool vis[maxn]; 15 int num[maxn]; 16 17 void addedge(int u,int v) 18 { 19 edge[tot].to=v; 20 edge[tot].nxt=head[u]; 21 head[u]=tot++; 22 } 23 24 void tarjan(int u) 25 { 26 int v; 27 low[u]=dfn[u]=++index; 28 stack[top++]=u; 29 vis[u]=true; 30 for ( int i=head[u];i!=-1;i=edge[i].nxt ) { 31 v=edge[i].to; 32

连通图练习总结

强颜欢笑 提交于 2020-03-20 08:04:18
连通图是图论基于联通的一个概念,在ACM中针对图论的考察一部分是也是基于连通图。针对这类问题的解题基本思路就是先求出对应的连通分量(有向图的强连通,无向图的双连通)对图进行简化,然后再结合其他算法计算。 1. POJ 3180 The Cow Prom 这个题如果能理解题目的话,怎么做就很明显了,能形成一个可以转圈的小群,就相当于一个强连通分量,需要注意的就是这个小群不可以只有一头牛。 #include <set> #include <map> #include <list> #include <stack> #include <queue> #include <ctime> #include <cmath> #include <cstdio> #include <vector> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #pragma comment(linker, "/STACK:1024000000,1024000000") #define IT iterator #define PB(x) push_back(x) #define CLR(a,b) memset(a,b,sizeof(a)) using namespace

Gym100221C Forbidden Subwords

拥有回忆 提交于 2020-03-06 22:28:45
Link 先建出AC自动机,然后把终止状态去掉,这样Trie图上的一条路径就对应了一个不包含Forbidden Subwords的字符串。 考虑如何对单向无限的串计数。单向无限的串是一条从根开始的无限长的路径,最后肯定会走到某个scc(自环也是强连通的)。 如果一个scc包含了不止一个简单环,那么我们就可以在两个环上来回走,答案就是 \(+\infty\) 。 那么现在所有的scc都是一个简单环。 如果某个从根出发的路径经过了两个scc,那么就可以在第一个scc上走任意多圈,答案也是 \(+\infty\) 。 那么现在一条合法的路径就是从根出发经过一些没有自环的单点走到一个scc,然后沿着scc走无限圈。 此时路径条数就是有限的了,可以在缩点之后的Trie图上求出。 现在考虑双向无限,相比于单向无限,我们可以比较近似的认为它是从某个scc开始到某个scc结束(可能是同一个)。 因此第二个判断答案为 \(+\infty\) 的条件就变成了存在一条经过三个scc路径。 最长路径和计数都可以在缩点之后的Trie图上求出。 注意要保留Trie图中的重边来判断是否是简单环。 #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<algorithm> const int N=10007;

hdu1814 Peaceful Commission

狂风中的少年 提交于 2020-03-05 06:18:24
hdu1814 Peaceful Commission 题意:2-sat裸题,打印字典序最小的 我写了三个 染色做法,正解 scc做法,不管字典序 scc做法,错误的字典序贪心 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int N = 2e4+5, M = 1e5+5; inline int read() { int x = 0, f = 1; char c = getchar(); while(c<'0' || c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();} return x * f; } int n, m; struct edge {int v, ne;} e[M]; int cnt, h[N]; inline void ins(int u, int v) { e[++cnt] = (edge) {v, h[u]}; h[u] = cnt; } inline int id(int x) {return ((x-1)^1)+1;} int col

UVA The Largest Clique (强联通分量 + 拓扑排序)

血红的双手。 提交于 2020-02-18 20:50:42
题目链接 题意:给你一张有向图,求一个节点数最大的节点集,使得该节点集中任意两个节点u,v。满足:要么u可达v,要么v可达u,要么互达。 思路:重新构造图,求出图中的所有scc,把同一个scc看做一个点,这样得到一张新的DAG,然后用拓扑排序求出DAG最长路即为答案。 #include <bits/stdc++.h> #define pb push_back using namespace std; const int maxn = 2020; int pre[maxn],low[maxn],scc[maxn],sz[maxn],d[maxn],dp[maxn]; int dfs_clock,scc_cnt; vector<int>G[maxn],G1[maxn]; stack<int>s; void dfs(int u) { pre[u] = low[u] = ++dfs_clock; s.push(u); for(int i=0;i<G[u].size();i++) { int v = G[u][i]; if(!pre[v]) { dfs(v); low[u] = min(low[v],low[u]); }else if(!scc[v])low[u] = min(low[u],pre[v]); } if(low[u] == pre[u]) { ++scc_cnt; while

牛客练习赛56 E 小雀和他的王国

点点圈 提交于 2020-02-13 01:55:42
题目链接: https://ac.nowcoder.com/acm/contest/3566/E 思路:tarjan缩点,桥重建图,dfs跑树的直径。 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 8 const int N = (int)2e5+100,mod = (int)1e9+7; 9 struct node{ 10 int to,nxt; 11 }e[N<<1]; 12 vector<pair<int,int> > cut; 13 int n,m,u,v,tot,tim,top,scc_num,bridge; 14 int head[N],dfn[N],low[N],s[N],scc_no[N],d[N]; 15 bool vis[N]; 16 17 ll quick(ll a,ll b){ 18 ll ans=1; 19 a=a%mod; 20 while(b!=0){ 21 if(b&1) ans=(ans*a)%mod; 22 b>>=1; 23 a=(a*a)%mod; 24 } 25 return ans; 26 } 27 28 inline

强连通分量SCC(Tarjan)

折月煮酒 提交于 2020-02-12 16:14:11
什么叫强连通分量呢~ 有向图强连通分量在有向图G中, 如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。 如果有向图G的每两个顶点都强连通,称G是一个强连通图。 有向图的极大强连通子图,称为强连通分量(strongly connected components)。 举个例子: 一般来讲,我们选择的都是常数较小的线性算法: Tarjan 实际上,学习过无向图的割点之后, SCC的tarjan算法更好理解 tarjan ta老人家也是用dfs解决这个问题的 考虑强连通分量C,设其阿红第一个被发现的点为x, 则C中的其他点都是x的后代 我们希望在x访问完成时立即输出C,现在问题的关键就是判断一个点是否是SCC中第一个被发现的点 如图是一棵dfs树 虚线表示一条或多条边 假设我们正在判断u是不是SCC中的第一个点, 如果我们发现从u的子节点出发可以到达u的祖先w,显然u,v,w在一个SCC中 因此u不是第一个发现的结点 如果我们发现从v出发最多只能到达u,那么u就是SCC中第一发现的结点 注意 这里的 到达 ,只能通过当前SCC中的点,而不能通过已经确定的SCC中的点 很像无向图割点的low数组 所以我们也可以用类似的方法维护出某一点能够到达的最早祖先 附上一张图 vector

强连通分量SCC(Tarjan)

女生的网名这么多〃 提交于 2020-02-12 16:10:02
什么叫强连通分量呢~ 有向图强连通分量在有向图G中, 如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。 如果有向图G的每两个顶点都强连通,称G是一个强连通图。 有向图的极大强连通子图,称为强连通分量(strongly connected components)。 举个例子: 一般来讲,我们选择的都是常数较小的线性算法: Tarjan 实际上,学习过无向图的割点之后, SCC的tarjan算法更好理解 tarjan ta老人家也是用dfs解决这个问题的 考虑强连通分量C,设其阿红第一个被发现的点为x, 则C中的其他点都是x的后代 我们希望在x访问完成时立即输出C,现在问题的关键就是判断一个点是否是SCC中第一个被发现的点 如图是一棵dfs树 虚线表示一条或多条边 假设我们正在判断u是不是SCC中的第一个点, 如果我们发现从u的子节点出发可以到达u的祖先w,显然u,v,w在一个SCC中 因此u不是第一个发现的结点 如果我们发现从v出发最多只能到达u,那么u就是SCC中第一发现的结点 注意 这里的 到达 ,只能通过当前SCC中的点,而不能通过已经确定的SCC中的点 很像无向图割点的low数组 所以我们也可以用类似的方法维护出某一点能够到达的最早祖先 附上一张图 vector

Tarjan算法---强联通分量

我们两清 提交于 2020-02-12 12:25:16
1、基础知识 在有向图G,如果两个顶点间至少存在一条路径,称两个顶点 强连通 (strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个 强连通图 。非强连通图有向图的极大强连通子图,称为 强连通分量 (strongly connected components)。 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4 两两可达 。{5},{6}也分别是两个强连通分量。 Tarjan算法是基于对图深度优先搜索的算法, 每个强连通分量为搜索树中的一棵子树 。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。栈中节点只有在其所属的强连通分量已经全部求出时,才会出栈。如果发现某节点u有边连到搜索树中栈里的节点v,则更新u的low 值为dfn[v](更新为low[v]也可以)。如果一个节点u已经DFS访问结束,而且此时其low值等于dfn值,则说明u可达的所有节点,都不能到达任何在u之前被DFS访问的节点 那么该节点u就是一个强连通分量在DFS搜索树中的根。此时将栈中所有节点弹出,包括u,就找到了一个强连通分量。 定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。    Low(u)=MIN{ DFN(u), Low(v),(u,v