题目链接:
点击打开链接
题目大意:
给出一个网络,问最少向几个点发布信息,才能传播到整张图,第二问问最少添加多少条边,能将这个这个图变成一个强连通图
题目分析:
首先第一问,一定要先强连通缩点,强连通分量当中的点可以相互到达,然后得到一个dag(有向无环联通图)图,所以只需判断新的图,有几个点入度为0即可
那么第二问,就是在这个DAG图中,只要所有点都有入度和出度即可,就是可以被其他点到达,也可以到达其他点,这样一定是一个强连通分量,(因为之前的图不存在环)
代码如下:
#include
#include
#include
#include
#include
#include
#define MAX 107
using namespace std;
int dfn[MAX],low[MAX],b[MAX];
int mark[MAX];
int times,cnt;
vector e[MAX];
stack s;
void tarjan ( int u )
{
dfn[u] = low[u] = ++times;
mark[u] = 1;
s.push ( u );
int len = e[u].size();
for ( int i = 0 ; i < len ; i++ )
{
int v = e[u][i];
if (!mark[v])
{
tarjan ( v );
low[u] = min ( low[u] , low[v] );
}
if (mark[v] == 1 )
low[u] = min ( low[u] , dfn[v] );
}
if ( dfn[u] == low[u] )
{
int temp;
do
{
temp = s.top();
b[temp] = cnt;
mark[temp] = 2;
s.pop();
}while ( temp != u );
cnt++;
}
}
void init ()
{
for ( int i = 0 ; i < MAX ; i++ )
e[i].clear();
while ( !s.empty()) s.pop();
times = cnt = 0;
}
int n;
int in[MAX],out[MAX];
int main ()
{
while (~scanf ( "%d" , &n ) )
{
init();
int x;
for ( int i = 1 ; i <= n ; i++ )
{
scanf ( "%d" , &x );
while ( x )
{
e[i].push_back(x);
scanf ("%d" , &x );
}
}
memset ( mark , 0 , sizeof ( mark ));
for ( int i = 1 ; i <= n ; i++ )
if ( !mark[i] ) tarjan ( i );
//cout << cnt << endl;
if ( cnt == 1 )
{
puts ( "1\n0");
continue;
}
memset ( in , 0 , sizeof ( in ));
memset ( out , 0 , sizeof ( out ));
int ans1,ans2;
ans1 = ans2 = 0;
for ( int i = 1 ; i <= n ; i++ )
{
int len = e[i].size();
for ( int j = 0 ; j < len ; j++ )
{
if (b[e[i][j]] == b[i] ) continue;
in[b[e[i][j]]]++;
out[b[i]]++;
}
}
/* cout << "blocks :" << endl;
for ( int i = 1 ; i <= 5 ; i++ )
cout << b[i] << " ";
cout << endl;*/
for ( int i = 0 ; i < cnt ; i++ )
{
//cout << in[i] << " " << out[i] << endl;
if ( !in[i] ) ans1++;
if ( !out[i] ) ans2++;
}
printf ( "%d\n%d\n" , ans1 , max ( ans1 , ans2 ));
}
}