1.输出各强连通分量
浅析强连通分量(Tarjan和kosaraju)Tarjan模板
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=10005;
const int maxm=100005;
int n,m,idx=0,k=1,Bcnt=0;
int head[maxn];
int ins[maxn]={0};
int dfn[maxn]={0},low[maxn]={0};
//int Belong[maxn];
stack <int> s;
struct edge
{
int v,next;
}e[maxm];
int min(int a,int b)
{
return a<b?a:b;
}
void adde(int u,int v)
{
e[k].v=v;
e[k].next=head[u];
head[u]=k++;
}
void tarjan(int u)
{
int v;
dfn[u]=low[u]=++idx;//每次dfs,u的次序号增加1
s.push(u);//将u入栈
ins[u]=1;//标记u在栈内
for(int i=head[u];i!=-1;i=e[i].next)//访问从u出发的边
{
v=e[i].v;
if(!dfn[v])//如果v没被处理过
{
tarjan(v);//dfs(v)
low[u]=min(low[u],low[v]);//u点能到达的最小次序号是它自己能到达点的最小次序号和连接点v能到达点的最小次序号中较小的
}
else if(ins[v])low[u]=min(low[u],dfn[v]);//如果v在栈内,u点能到达的最小次序号是它自己能到达点的最小次序号和v的次序号中较小的
}
if(dfn[u]==low[u])
{
Bcnt++;
do
{
v=s.top();
s.pop();
ins[v]=0;
// Belong[v]=Bcnt; //把属于第Bcnt个强连通分量的节点v的Belong都为Bcnt,如果节点3,4属于第2个强连通分量,则使 Belong[3],Belong[4]都等于2;
}while(u != v);
}
}
void work()
{
for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
// printf("\n");
// for(int i = 1;i <= 6;i++)printf("%d %d\n",dfn[i],low[i]);
// printf("共有%d强连通分量,它们是:\n",Bcnt);
if(Bcnt==1){
printf("Yes\n");
}else{
printf("No\n");
}
// for(int i=1;i<=Bcnt;i++)
// {
// printf("第%d个:",i);
// for(int j=1;j<=n;j++)
// {
// if(Belong[j]==i)printf("%d ",j);
// }
// printf("\n");
// }
}
int main()
{
int a,b;
while(~scanf("%d%d",&n,&m)){
idx=0,k=1,Bcnt=0;
memset(ins,0,sizeof(ins));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
if(n==0&&m==0){
return 0;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
adde(a,b);
}
work();
}
}
2.割点模板
例题(求割点数目)
如果想输出各个割点,只需通过迭代器访问set即可。
# include<iostream>
# include<cstdio>
# include<set>
# include<vector>
# include<cstring>
# define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1000;
int low[maxn],dfn[maxn],root,now,m;
vector<int>g[maxn];
set<int>ans; //ans用来盛装割点
void init(){
now=0;
mem(dfn,0);
mem(low,0);
ans.clear();
for( int i = 0; i < maxn; i++ ) g[i].clear();
}
void addedge(int u,int v){
g[u].push_back(v);
g[v].push_back(u);
}
void tarjan(int u,int fa){
low[u]=dfn[u]=++now;
int len=g[u].size();
int son=0;
for(int i=0;i<len;++i){
int v=g[u][i];
if(v==fa)continue;
if(!dfn[v]){
tarjan(v,u);
son++;
low[u]=min(low[u],low[v]);
if(u==root&&son>1){
ans.insert(u);
}else if(u!=root&&dfn[u]<=low[v]){
ans.insert(u);
}
}else{
low[u]=min(low[u],dfn[v]);
}
}
}
int main(){
while(scanf("%d",&m)&&m!=0)
{
init();
int n;
while(scanf("%d",&n)&&n!=0)
{
while(getchar()!='\n')
{
int a;
scanf("%d",&a);
addedge(n,a);
}
}
root=1;
tarjan(1,-1);
printf("%d\n",ans.size());
}
return 0;
}
3.割边(桥)模板
# include<iostream>
# include<cstdio>
# include<set>
# include<vector>
# include<cstring>
# include<algorithm>
# define mem(a,b) memset(a,b,sizeof(a))
# define p pair<int ,int>
using namespace std;
const int maxn=1e5+5;
int low[maxn],dfn[maxn],now,ecnt;
vector<int>g[maxn];
//set<p>ans; //pair型的ans同时容纳一条边的两个端点 (不知为啥会wa)
struct Ans{
int u,v;
}ans[maxn]; //ans容纳一条边的两个端点
void init(){
ecnt=0;
now=0;
mem(dfn,0);
mem(low,0);
mem(ans,0);
for( int i = 0; i < maxn; i++ ) g[i].clear();
}
int cmp(Ans a,Ans b){
if(a.u>b.u) return a.u<b.u;
else if(a.u==b.u && a.v>b.v) return a.v<b.v;
return 1;
}
void addedge(int u,int v){
g[u].push_back(v);
g[v].push_back(u);
}
void tarjan(int u,int fa){
low[u]=dfn[u]=++now;
int len=g[u].size();
for(int i=0;i<len;++i){
int v=g[u][i];
if(v==fa)continue;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
if (dfn[u] < low[v]){
//ans.insert(make_pair(min(u,v), max(u,v)));
int a,b;
a=u,b=v;
if(a>b) swap(a,b);
ans[ecnt].u=a,ans[ecnt].v=b;
ecnt++;
}
}else{
low[u]=min(low[u],dfn[v]);
}
}
}
int main(){
int n, x, y, m;
while (scanf("%d", &n) != EOF) {
init();
for (int i = 0; i < n; ++i) g[i].clear();
for (int i = 0; i < n; ++i) {
scanf("%d (%d)", &x, &m);
for (int j = 0; j < m; ++j) {
scanf("%d", &y);
addedge(x, y);
}
}
for (int i = 0; i < n; ++i) {
if (dfn[i]) continue;
tarjan(i, i);
}
//int sum = ans.size();
// printf("%d critical links\n", sum);
// set<p>::iterator it=ans.begin(); //迭代器访问ans
// for (;it!=ans.end();it++) {
// printf("%d - %d\n", *it); //一个*it包含pair中的两个int (wa)
// }
sort(ans,ans+ecnt,cmp);
cout<<ecnt<<" critical links"<<endl;
for(int i=0;i<ecnt;i++){
printf("%d - %d\n",ans[i].u,ans[i].v);
}
printf("\n");
}
return 0;
}
4.缩点
#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
using namespace std;
const int maxm=50050;
int n,m,idx=0,k=1,Bcnt=0;
int head[maxm];
int ins[maxm]={0};
int dfn[maxm]={0},low[maxm]={0};
int Belong[maxm];
int outdegree[maxm];
stack <int> s;
struct edge
{
int v,next;
}e[maxm];
int min(int a,int b)
{
return a<b?a:b;
}
void adde(int u,int v)
{
e[k].v=v;
e[k].next=head[u];
head[u]=k++;
}
void tarjan(int u) //仍是不变的模板
{
int v;
dfn[u]=low[u]=++idx;//每次dfs,u的次序号增加1
s.push(u);//将u入栈
ins[u]=1;//标记u在栈内
for(int i=head[u];i!=-1;i=e[i].next)//访问从u出发的边
{
v=e[i].v;
if(!dfn[v])//如果v没被处理过
{
tarjan(v);//dfs(v)
low[u]=min(low[u],low[v]);//u点能到达的最小次序号是它自己能到达点的最小次序号和连接点v能到达点的最小次序号中较小的
}
else if(ins[v])low[u]=min(low[u],dfn[v]);//如果v在栈内,u点能到达的最小次序号是它自己能到达点的最小次序号和v的次序号中较小的
}
if(dfn[u]==low[u])
{
Bcnt++;
do
{
v=s.top();
s.pop();
ins[v]=0;
Belong[v]=Bcnt; //把属于第Bcnt个强连通分量的节点v的Belong都为Bcnt,如果节点3,4属于第2个强连通分量,则使 Belong[3],Belong[4]都等于2;
}while(u != v);
}
}
void work()
{
for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
// printf("\n");
// for(int i = 1;i <= 6;i++)printf("%d %d\n",dfn[i],low[i]);
// printf("共有%d强连通分量,它们是:\n",Bcnt);
// if(Bcnt==1){
// printf("Yes\n");
// }else{
// printf("No\n");
// }
// for(int i=1;i<=Bcnt;i++)
// {
// printf("第%d个:",i);
// for(int j=1;j<=n;j++)
// {
// if(Belong[j]==i)printf("%d ",j);
// }
// printf("\n");
// }
for(int i=1;i<=n;i++){ //求每个强连通分量的出度(如果某个强连通分量包含多个点,将他们缩为一个超级点)
for(int j=head[i];j!=-1;j=e[j].next){
int v=e[j].v;
if(Belong[i]!=Belong[v])
outdegree[Belong[i]]++;
}
}
int sum=0,temp,ans=0;
for(int i=1; i<=Bcnt; i++)
{
if(!outdegree[i]) //出度为零,并且这样的点只有一个才输出1,否则输出0
sum++,temp=i;
}
if(sum==1)
{
for(int i=1; i<=n; i++)
if(Belong[i]==temp)
ans++;
}
else
ans=0;
printf("%d\n",ans);
}
int main()
{
int a,b;
while(~scanf("%d%d",&n,&m)){
idx=0,k=1,Bcnt=0;
memset(ins,0,sizeof(ins));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
adde(a,b);
}
work();
}
}
阿里云建站—为企业提供互联网“快”服务
2020年因为一场突如其来的疫情,不少企业受到了严重冲击,疫情的冲击力对传统“纯线
下”行业的危害最大,互联网女皇玛丽·米克(MaryMeeker)4月17日发布了著名的年度互
联网趋势报告,报告中指出:拥有强大的互联网线上线下融合能力的企业在疫情中的表现最好,
线上线下融合的趋势已经存在一段时间了,但是疫情让这种需求变得更加的迫切。
如果你的企业完全依附于传统的、纯线下的经验模式,那么在2020年你将“必死无疑”,
一场巨大的,前所未有的互联网革命已经到来!
阿里云建站为了助力各行各业复工复产,疫情期间“马不停蹄”为数以万计的企业快速完成
建站,为他们朝着“线上线下融合”或者“纯线上”的互联网经营模式迈进,打下了坚实的基础。
“云·速成美站”模板建站1天就能上线,不懂技术没关系,打字就能建网站。千套网站模
板免费提供,百元就能建官网,一价全包,无任何隐形消费。
“云·企业官网”定制建站1周就能上线,高端量身定制建站,千元建官网无需自己动手,
建站专家1对1网站策划及设计,专业省心之选。
疫情,是一场大浪淘沙,每一次危机背后都隐藏着机会,危机越大,机会也越大。大环境
已经改变,如果你不努力不去改变来迎合这个大环境,那你必将被淘汰。
阿里云助力企业建站,优惠多多,福利多多,详情请点击如下链接
红包+折扣,阿里云上云大礼包!https://www.aliyun.com/minisite/goods?userCode=