普通的tarjan
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <queue>
#include <stack>
using namespace std;
#define M 10010
int low[M];//最小的子节点,相当于一棵树最开始的那个点
int bfn[M];//记录这个点搜索的次序编号(时间戳)
int m, n;
int cnt, cat;//时间戳、强连通分量的数量
int vit[M];//访问标记
vector<int>Map[M];
stack<int>S;
void tarjan(int x)
{
low[x]=bfn[x]=++cnt;//刚开始x的最小子节点就是自身的时间戳
vit[x]=1;
S.push(x);
for(int i=0; i<Map[x].size(); i++)//遍历与x联通的所有点
{
int t=Map[x][i];
if(!vit[t])//未被访问过
{
tarjan(t);
low[x]=min(low[x], low[t]);//x的最小子节点取最小
}
else
low[x]=min(low[x], bfn[t]);
}
if(low[x]==bfn[x])//如果x的最小子节点就是自己
{
cat++;//集合数+1
while(!S.empty())
{
int t=S.top();
S.pop();
vit[t]=0;
if(x==t)
break;
}
}
}
void solve()
{
for(int i=1; i<=n; i++)
if(!bfn[i])//如果没被访问过
tarjan(i);
}
void init()
{
while(!S.empty())
S.pop();
for(int i=1; i<=n; i++)
Map[i].clear();
memset(low, 0, sizeof(low));
memset(bfn, 0, sizeof(bfn));
memset(vit, 0, sizeof(vit));
cnt=cat=0;
}
int main()
{
while(scanf("%d%d", &n, &m), n||m)
{
init();
/*for(int i=0; i<m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
Map[a].push_back(b);
}*/ //读入路径信息
solve();
if(cat>1)//如果集合数大于1,题目要求只有一个集合
printf("No\n");
else
printf("Yes\n");
}
return 0;
}
缩点求出度
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>
#include <stack>
using namespace std;
#define M 10010
int low[M];//最小的子节点,相当于一棵树最开始的那个点
int bfn[M];//记录这个点搜索的次序编号(时间戳)
int m, n;
int cnt, cat;//时间戳,集合的序号
int vit[M];//标记数组
int point_setnum[M];//某个数所在集合的编号
vector<int> point_list[M];//某个集合所含的元素
int out[M];//某个集合的出度
vector<int>Map[M];//存路径
stack<int>S;
void tarjan(int x)
{
low[x]=bfn[x]=++cnt;
vit[x]=1;
S.push(x);
for(int i=0; i<Map[x].size(); i++)
{
int t=Map[x][i];
if(!bfn[t])
{
tarjan(t);
low[x]=min(low[x], low[t]);
}
else if(vit[t])
low[x]=min(low[x], bfn[t]);
}
if(low[x]==bfn[x])
{
cat++;
while(!S.empty())
{
int t=S.top();
S.pop();
vit[t]=0;
point_list[cat].push_back(t);//将元素t加入编号为cat的集合中**
point_setnum[t]=cat;//元素t所在集合编号为cat**
if(x==t)
break;
}
}
}
void solve()
{
for(int i=1; i<=n; i++)
if(!bfn[i])
tarjan(i);
}
void init()
{
memset(low, 0, sizeof(low));
memset(bfn, 0, sizeof(bfn));
memset(vit, 0, sizeof(vit));
cnt=cat=0;
while(!S.empty())
S.pop();
for(int i=1; i<=n; i++)
Map[i].clear();
}
int main()
{
while(scanf("%d%d", &n, &m)!=EOF)
{
/*for(int i=0; i<m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
Map[a].push_back(b);
}*/ //读入路径信息
solve();
for(int i=1; i<=n; i++)//n个点遍历
{
for(int j=0; j<Map[i].size(); j++)//每个点连接的点
{
int t=Map[i][j];
if(point_setnum[i]!=point_setnum[t])//若i点和与i相连的点在两个强连通分量中
out[point_setnum[i]]++;//i点所在集合的出度+1
}
}
//后面根据题意结合out[]输出
}
return 0;
}
求割点数量
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>
#include <stack>
using namespace std;
#define inf 99999999
#define N 1005
int low[N];
int dfn[N];
int n;
int cnt;//时间戳
int cut[N];//记录是否是割点
vector<int>Map[N];
void tarjan(int x, int fa)//求割点数量模板
{
low[x]=dfn[x]= ++cnt;
int childs=0;
for(int i=0; i<Map[x].size(); i++)
{
int t=Map[x][i];
if(!dfn[t])
{
childs++;
tarjan(t, x);
low[x]=min(low[x], low[t]);
if(low[t]>=dfn[x]&&fa>0)
cut[x]=1;
}
else if(fa!=t)
low[x]=min(low[x], dfn[t]);
}
if(fa<0)
cut[x]= (childs>=2) ? 1:0;
}
void solve()
{
tarjan(1, -1);
}
void init()
{
memset(low, 0, sizeof low);
memset(dfn, 0, sizeof dfn);
memset(cut, 0, sizeof cut);
cnt=0;
for(int i=1; i<=n; i++)
Map[i].clear();
}
int main()
{
while(scanf("%d", &n)&&n)
{
init();
/*int u, v;
while(scanf("%d", &u)&&u)//读入比较麻烦
{
while(getchar()!='\n')
{
scanf("%d", &v);
Map[u].push_back(v);
Map[v].push_back(u);
}
}*/ //这一部分是读入数据,将点与点的关系存在Map[]中
solve();
int ans=0;
for(int i=1; i<=n; i++)//统计割点数
if(cut[i])
ans++;
printf("%d\n", ans);
}
return 0;
}