1、题目类型:图论、强连通分量、Tarjan算法。
2、解题思路:(1)建立图的邻接表;(2)Trajan算法求解并记录强连通分量;(3)判断强连通分量的入度,当存在多个出度为0时,输出0;当只存在唯一出度为0的强连通分量,则输出其内部节点的个数。
3、注意事项:图用邻接表表示,矩阵表示MLE;注意M=0的情况。
4、实现方法:
#include
<
iostream
>
#include < stack >
using namespace std;
struct TNode
{
int data;
TNode * next;
};
int n,m,index,cnt,bcnt;
int dfn[ 10010 ],low[ 10010 ];
int a[ 50010 ],b[ 50010 ],flag[ 10010 ];
TNode * map[ 10010 ],data[ 500100 ];
bool vis[ 10010 ];
stack < int > S;
void Tarjan( int v)
{
TNode * tmp;
dfn[v] = low[v] =++ cnt;
vis[v] = true ;
S.push(v);
for (tmp = map[v];tmp != NULL;tmp = tmp -> next)
{
int i = tmp -> data;
if ( ! dfn[i])
{
Tarjan(i);
if (low[v] > low[i])
low[v] = low[i];
}
else if (vis[i] && low[v] > dfn[i])
{
low[v] = dfn[i];
}
}
if (low[v] == dfn[v])
{
bcnt ++ ;
int j;
do
{
j = S.top();
S.pop();
// 用于标示点j在第bcnt个强连通分量里面
flag[j] = bcnt;
} while (j != v);
}
}
int main()
{
int i,ans,pos;
TNode * P, * pre;
cin >> n >> m;
if (m == 0 )
{
cout << 0 << endl;
return 0 ;
}
// 建立邻接表
for (i = 1 ;i <= m;i ++ )
{
cin >> a[i] >> b[i];
P =& data[index ++ ];
P -> data = b[i];
if (map[a[i]] == NULL)
{
map[a[i]] = P;
}
else
{
pre = map[a[i]] -> next;
P -> next = pre;
map[a[i]] -> next = P;
}
}
for (i = 1 ;i <= n;i ++ )
{
if ( ! dfn[i])
Tarjan(i);
}
memset(vis, 0 , sizeof (vis));
for (i = 1 ;i <= m;i ++ )
{
if (flag[a[i]] != flag[b[i]])
vis[flag[a[i]]] = 1 ;
}
cnt = 0 ;
for (i = 1 ;i <= bcnt;i ++ )
{
if ( ! vis[i])
{
cnt ++ ;
pos = i;
}
}
if (cnt > 1 )
{
cout << 0 << endl;
}
else
{
ans = 0 ;
for (i = 1 ;i <= n;i ++ )
if (flag[i] == pos)
ans ++ ;
cout << ans << endl;
}
return 0 ;
}
#include < stack >
using namespace std;
struct TNode
{
int data;
TNode * next;
};
int n,m,index,cnt,bcnt;
int dfn[ 10010 ],low[ 10010 ];
int a[ 50010 ],b[ 50010 ],flag[ 10010 ];
TNode * map[ 10010 ],data[ 500100 ];
bool vis[ 10010 ];
stack < int > S;
void Tarjan( int v)
{
TNode * tmp;
dfn[v] = low[v] =++ cnt;
vis[v] = true ;
S.push(v);
for (tmp = map[v];tmp != NULL;tmp = tmp -> next)
{
int i = tmp -> data;
if ( ! dfn[i])
{
Tarjan(i);
if (low[v] > low[i])
low[v] = low[i];
}
else if (vis[i] && low[v] > dfn[i])
{
low[v] = dfn[i];
}
}
if (low[v] == dfn[v])
{
bcnt ++ ;
int j;
do
{
j = S.top();
S.pop();
// 用于标示点j在第bcnt个强连通分量里面
flag[j] = bcnt;
} while (j != v);
}
}
int main()
{
int i,ans,pos;
TNode * P, * pre;
cin >> n >> m;
if (m == 0 )
{
cout << 0 << endl;
return 0 ;
}
// 建立邻接表
for (i = 1 ;i <= m;i ++ )
{
cin >> a[i] >> b[i];
P =& data[index ++ ];
P -> data = b[i];
if (map[a[i]] == NULL)
{
map[a[i]] = P;
}
else
{
pre = map[a[i]] -> next;
P -> next = pre;
map[a[i]] -> next = P;
}
}
for (i = 1 ;i <= n;i ++ )
{
if ( ! dfn[i])
Tarjan(i);
}
memset(vis, 0 , sizeof (vis));
for (i = 1 ;i <= m;i ++ )
{
if (flag[a[i]] != flag[b[i]])
vis[flag[a[i]]] = 1 ;
}
cnt = 0 ;
for (i = 1 ;i <= bcnt;i ++ )
{
if ( ! vis[i])
{
cnt ++ ;
pos = i;
}
}
if (cnt > 1 )
{
cout << 0 << endl;
}
else
{
ans = 0 ;
for (i = 1 ;i <= n;i ++ )
if (flag[i] == pos)
ans ++ ;
cout << ans << endl;
}
return 0 ;
}