http://acm.hdu.edu.cn/showproblem.php?pid=2767

问最少添加几条边使得图为强连通。

  tarjan跑一下,然后对强连通分量缩点,找下此时出度为零和入度为零的点数输出较大者即可。

  tarjan,dfn数组也同时起到了标记的作用,如果未标记说明此时的边就是dfs树上的边,否则的话,如果v已经处于某个scc中说明这条边是交叉边,不用考虑(因为一定无对应的回边,有的话这个点就应该和v属于同一个scc,与过程矛盾)。否则就是回边了,和求桥和割点的方法类似求dfn以及low数组。

  最后如果low[u]==dfn[u]说明u沿着他的孩子能回到他自己,这就形成了一个环,环上的所有点构成了一个scc,不断出栈直到u出现为止统计下scc。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<stack>
#include<deque>
#include<bitset>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<cstdlib>
#include<ctype.h>
#include<ctime>
#include<functional>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define debug puts("debug")
#define mid ((L+R)>>1)
#define lc (id<<1)
#define rc (id<<1|1)
const int maxn=;
const int maxm=;
const double PI=acos(-1.0);
const double eps=1e-;
const LL mod=1e9+;
LL gcd(LL a,LL b){return b==?a:gcd(b,a%b);}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL qpow(LL a,LL b,LL c){LL r=; for(;b;b>>=,a=a*a%c)if(b&)r=r*a%c;return r;}
template<class T>
void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
struct Edge{int u,v,w,next;}; int dfn[maxn],low[maxn],scc[maxn],scc_cnt,sum;
int in[maxn],out[maxn];
vector<int>g[maxn];
stack<int>S;
void dfs(int u){
dfn[u]=low[u]=++sum;
S.push(u);
for(int v:g[u]){
if(!dfn[v]){
dfs(v);
low[u]=min(low[u],low[v]);
}else if(!scc[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
++scc_cnt;
int x=-;
for(;;){
x=S.top();S.pop();
scc[x]=scc_cnt;
if(x==u)break;
}
}
}
int main(){
int t,n,m,i,j,k,u,v;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(i=;i<=n;++i)g[i].clear(),dfn[i]=low[i]=scc[i]=;
sum=scc_cnt=;
while(!S.empty())S.pop();
while(m--){
scanf("%d%d",&u,&v);
g[u].pb(v);
}
for(i=;i<=n;++i){
if(!dfn[i]){
dfs(i);
}
}
if(scc_cnt==){
cout<<<<endl;
continue;
}
for(i=;i<=scc_cnt;++i)in[i]=out[i]=;
for(u=;u<=n;++u){
for(int v:g[u]){
if(scc[u]!=scc[v]){
in[scc[v]]=out[scc[u]]=;
}
}
}
int a=,b=;
for(i=;i<=scc_cnt;++i)a+=in[i],b+=out[i];
cout<<max(a,b)<<endl;
}
return ;
}

Kosaraju:先按原图跑一编按后序顺序编号,然后按照编号从大到小跑反向图,跑一次就是一个scc。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<stack>
#include<deque>
#include<bitset>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<cstdlib>
#include<ctype.h>
#include<ctime>
#include<functional>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define debug puts("debug")
#define mid ((L+R)>>1)
#define lc (id<<1)
#define rc (id<<1|1)
const int maxn=;
const int maxm=;
const double PI=acos(-1.0);
const double eps=1e-;
const LL mod=1e9+;
LL gcd(LL a,LL b){return b==?a:gcd(b,a%b);}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL qpow(LL a,LL b,LL c){LL r=; for(;b;b>>=,a=a*a%c)if(b&)r=r*a%c;return r;}
template<class T>
void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
struct Edge{int u,v,w,next;}; int vis[maxn],scc[maxn],scc_cnt;
int in[maxn],out[maxn];
vector<int>g[maxn],g2[maxn],q;
void dfs1(int u){
if(vis[u])return;vis[u]=;
for(int v:g[u])dfs1(v);q.pb(u);
}
void dfs2(int u){
if(scc[u])return;scc[u]=scc_cnt;
for(int v:g2[u])dfs2(v);
}
int main(){
int t,n,m,i,j,k,u,v;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
q.clear();
for(i=;i<=n;++i)g[i].clear(),g2[i].clear(),vis[i]=scc[i]=;
scc_cnt=;
while(m--){
scanf("%d%d",&u,&v);
g[u].pb(v);
g2[v].pb(u);
}
for(i=;i<=n;++i){
if(!vis[i]){
dfs1(i);
}
}
for(i=n-;i>=;--i){
if(!scc[q[i]]){
++scc_cnt;
dfs2(q[i]);
}
}
// cout<<"FUCK: "<<scc_cnt<<endl;
if(scc_cnt==){
cout<<<<endl;
continue;
}
for(i=;i<=scc_cnt;++i)in[i]=out[i]=;
for(u=;u<=n;++u){
for(int v:g[u]){
if(scc[u]!=scc[v]){
in[scc[v]]=out[scc[u]]=;
}
}
}
int a=,b=;
for(i=;i<=scc_cnt;++i)a+=in[i],b+=out[i];
cout<<max(a,b)<<endl; }
return ;
}

HDU-2767-tarjan/Kosaraju求scc的更多相关文章

  1. tarjan算法求scc & 缩点

    前置知识 图的遍历(dfs) 强连通&强连通分量 对于有向图G中的任意两个顶点u和v存在u->v的一条路径,同时也存在v->u的路径,我们则称这两个顶点强连通.以此类推,强连通分量 ...

  2. 转载 - Tarjan算法(求SCC)

    出处:http://blog.csdn.net/xinghongduo/article/details/6195337 说到以Tarjan命名的算法,我们经常提到的有3个,其中就包括本文所介绍的求强连 ...

  3. HDU 2874 /// tarjan离线求森林里两点的距离

    题目大意: 在一个森林里 询问 u v 两点 若不能到达输出 "Not connected" 否则输出两点距离 https://blog.csdn.net/keyboarderqq ...

  4. HDU 2586 /// tarjan离线求树上两点的LCA

    题目大意: 询问一棵树里 u 到 v 的距离 可由 dis[ u到根 ] + dis[ v到根 ] - 2*dis[ lca(u,v) ] 得到 https://blog.csdn.net/csyzc ...

  5. 间谍网络——tarjan求SCC

    洛谷传送门 看着这道题给人感觉就是tarjan求SCC,然而还得判断是否能控制全部间谍,这就得先从可以贿赂的点dfs一遍. 如果没有全部被标记了,就输出NO,再从没被标记的点里找最小的标号. 如果全被 ...

  6. tarjan 缩点 求 scc

    算法学自 BYVoid https://www.byvoid.com/zhs/blog/scc-tarjan/ 这个写得很清楚了 当然 你可能不这么认为 而且 如果是让我 一开始就从这个博客 学 ta ...

  7. HDU 1269 -- 迷宫城堡【有向图求SCC的数目 &amp;&amp; 模板】

    迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  8. HDU 1269 迷宫城堡 tarjan算法求强连通分量

    基础模板题,应用tarjan算法求有向图的强连通分量,tarjan在此处的实现方法为:使用栈储存已经访问过的点,当访问的点离开dfs的时候,判断这个点的low值是否等于它的出生日期dfn值,如果相等, ...

  9. 有向图 加最少的边 成为强连通分量的证明 poj 1236 hdu 2767

    poj 1236: 题目大意:给出一个有向图, 任务一: 求最少的点,使得从这些点出发可以遍历整张图  任务二: 求最少加多少边 使整个图变成一个强连通分量. 首先任务一很好做, 只要缩点 之后 求 ...

随机推荐

  1. Images之base image

    Create a base image Most Dockerfiles start from a parent image. If you need to completely control th ...

  2. 配置httpd支持https

    1.首先为192.168.108.159创建私有CA #cd /etc/pki/CA # (umask 077;openssl genrsa -out private/cakey.pem 2048) ...

  3. HDU 4320 Arcane Numbers 1(质因子包含)

    http://acm.hdu.edu.cn/showproblem.php?pid=4320 题意: 给出A,B,判断在A进制下的有限小数能否转换成B进制下的有限小数. 思路: 这位博主讲得挺不错的h ...

  4. 51nod 1069 Nim游戏 + BZOJ 1022: [SHOI2008]小约翰的游戏John(Nim游戏和Anti-Nim游戏)

    首先,51nod的那道题就是最简单的尼姆博弈问题. 尼姆博弈主要就是判断奇异局势,现在我们就假设有三个石子堆,最简单的(0,n,n)就是一个奇异局势,因为无论先手怎么拿,后手总是可以在另一堆里拿走相同 ...

  5. vue动态改变样式

    <i class="el-icon-arrow-left" :style="{'color': deadColorArr[index]}" @click= ...

  6. Vue运行报错--eslint

    Errors:? 1? http://eslint.org/docs/rules/no-trailing-spacesYou may use special comments to disable s ...

  7. NoSQL(not only struts query language)的简单介绍

    为什么需要NoSQL? 互联网自扩大规模来一直面临3个问题 1.High performance高并发 一个网站开发实时生成动态页面可能会存在高并发请求的需求,硬盘IO已经无法接受 2.Huge St ...

  8. Java的CountDownLatch和CyclicBarrier的理解和区别

    CountDownLatch和CyclicBarrier的功能看起来很相似,不易区分,有一种谜之的神秘.本文将通过通俗的例子并结合代码讲解两者的使用方法和区别. CountDownLatch和Cycl ...

  9. [原][粒子特效][spark]粒子系统system、主节点group、渲染器render

    深入浅出spark粒子特效连接:https://www.cnblogs.com/lyggqm/p/9956344.html system: A class defining a complete sy ...

  10. JNI手动释放内存(避免内存泄露)

    . 哪些需要手动释放? 不要手动释放(基本类型): jint , jlong , jchar 需要手动释放(引用类型,数组家族): jstring,jobject ,jobjectArray,jint ...