学长写的:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define maxn 10005
int dfn[maxn];///代表最先遍历到这个点的时间
int low[maxn];///这个点所能到达之前最早的时间点
int Father[maxn];///保存这个节点的父亲节点
int n, m, Time, top;///Time 时间点, top用于栈操作
vector<vector<int> > G;
void Init()
{
G.clear();
G.resize(n+1);
memset(low, 0, sizeof(low));
memset(dfn, 0, sizeof(dfn));
memset(Father, 0, sizeof(Father));
Time = 0;
}
void Tarjan(int u,int fa)
{
low[u] = dfn[u] = ++Time;
Father[u] = fa;
int len = G[u].size(), v;
for(int i=0; i<len; i++)
{
v = G[u][i];
if(!dfn[v])
{
Tarjan(v, u);
low[u] = min(low[u], low[v]);
}
else if(fa != v)///假如我们在这里写上了 low[u] = min(low[v], low[u]),那么就相当于我们由v回到了v之前的节点
low[u] = min(dfn[v], low[u]);
}
}
void solve()
{/**
求割点
一个顶点u是割点,当且仅当满足(1)或(2)
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。
(也就是说 V 没办法绕过 u 点到达比 u dfn要小的点)
注:这里所说的树是指,DFS下的搜索树*/
int RootSon = 0, ans = 0;///根节点儿子的数量
bool Cut[maxn] = {false};///标记数组,判断这个点是否是割点
Tarjan(1,0);
for(int i=2; i<=n; i++)
{
int v = Father[i];
if(v == 1)///也是就说 i的父亲是根节点
RootSon ++;
else if(dfn[v] <= low[i])
Cut[v] = true;
}
for(int i=2; i<=n; i++)
{
if(Cut[i])
ans ++;
}
if(RootSon > 1)
ans++;
printf("%d ", ans);
}
int main()
{
while(scanf("%d", &n), n)
{
int a, b;
char ch;
Init();
while(scanf("%d", &a), a)
{
while(scanf("%d%c",&b,&ch))
{
G[a].push_back(b);
G[b].push_back(a);
if(ch == ' ')
break;
}
}
solve();
}
return 0;
}
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define maxn 10005
int dfn[maxn];///代表最先遍历到这个点的时间
int low[maxn];///这个点所能到达之前最早的时间点
int Father[maxn];///保存这个节点的父亲节点
int n, m, Time, top;///Time 时间点, top用于栈操作
vector<vector<int> > G;
void Init()
{
G.clear();
G.resize(n+1);
memset(low, 0, sizeof(low));
memset(dfn, 0, sizeof(dfn));
memset(Father, 0, sizeof(Father));
Time = 0;
}
void Tarjan(int u,int fa)
{
low[u] = dfn[u] = ++Time;
Father[u] = fa;
int len = G[u].size(), v;
for(int i=0; i<len; i++)
{
v = G[u][i];
if(!dfn[v])
{
Tarjan(v, u);
low[u] = min(low[u], low[v]);
}
else if(fa != v)///假如我们在这里写上了 low[u] = min(low[v], low[u]),那么就相当于我们由v回到了v之前的节点
low[u] = min(dfn[v], low[u]);
}
}
void solve()
{/**
求割点
一个顶点u是割点,当且仅当满足(1)或(2)
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且满足存在(u,v)为树枝边(或称 父子边,即u为v在搜索树中的父亲),使得 dfn(u)<=low(v)。
(也就是说 V 没办法绕过 u 点到达比 u dfn要小的点)
注:这里所说的树是指,DFS下的搜索树*/
int RootSon = 0, ans = 0;///根节点儿子的数量
bool Cut[maxn] = {false};///标记数组,判断这个点是否是割点
Tarjan(1,0);
for(int i=2; i<=n; i++)
{
int v = Father[i];
if(v == 1)///也是就说 i的父亲是根节点
RootSon ++;
else if(dfn[v] <= low[i])
Cut[v] = true;
}
for(int i=2; i<=n; i++)
{
if(Cut[i])
ans ++;
}
if(RootSon > 1)
ans++;
printf("%d ", ans);
}
int main()
{
while(scanf("%d", &n), n)
{
int a, b;
char ch;
Init();
while(scanf("%d", &a), a)
{
while(scanf("%d%c",&b,&ch))
{
G[a].push_back(b);
G[b].push_back(a);
if(ch == ' ')
break;
}
}
solve();
}
return 0;
}
自己又写的
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define N 110
#define min(a, b) a<b?a:b
int n, father[N];
int visit[N], rode[N];
int rootson, ans, t, inter[N];
vector<vector<int> >G;
void Init()
{
G.clear();
G.resize(n+1);
rootson=0;
ans=0;
t=0;
memset(inter, 0, sizeof(inter));
memset(visit, 0, sizeof(visit));
memset(rode, 0, sizeof(rode));
memset(father, 0, sizeof(father));
}
void Tarjan(int u, int fu)
{
visit[u]=rode[u]=++t;
father[u]=fu;
int len=G[u].size();
for(int i=0; i<len; i++)
{
int v=G[u][i];
if(!visit[v])
{
Tarjan(v, u);
rode[u]=min(rode[u], rode[v]);
}
else if(v!=fu)
{
rode[u]=min(visit[v], rode[u]);
}
}
}
void solve()
{
Tarjan(1, 0);
for(int i=2; i<=n; i++)
{
int v=father[i];
if(v==1)
rootson++;
else if(visit[v]<=rode[i])//这一点可能不理解吧
inter[v]=1;
}
for(int i=2; i<=n; i++)
{
if(inter[i])
ans++;
}
if(rootson>1)
ans++;
printf("%d
", ans);
}
int