題意:
給定一個有向圖,求下面兩個量:
1 :最少從幾個點出發能遍歷全圖。
2 :最少加幾條邊能使原圖強聯通。
解法:“最少從幾個點出發能遍歷全圖”的點數是將原圖縮點後入度爲零的點的個數。
“最少加幾條邊能使原圖強聯通”的邊數是將原圖縮點後出度爲零的點和入讀爲零的點中的最大值。
(注意強聯通圖的情況)#include<iostream>
using namespace std;
const int MAXN =101;
int DFN[MAXN];
int LOW[MAXN];
int instack[MAXN];
int Stap[MAXN];
int Belong[MAXN];
bool in_num[MAXN];
bool out_num[MAXN];
bool map[MAXN][MAXN];
struct edge
{
int v,next;
}vetex[50001];
int head[MAXN];
int Stop,Bcnt,Dindex,N,k;
void add(int a,int b)
{
vetex[k].v = b;
vetex[k].next = head[a];
head[a] = k;k++;
}
void tarjan(int i)
{
int j;
DFN[i]=LOW[i]=++Dindex;
instack[i]=true;
Stap[++Stop]=i;
for (int k=head[i];k;k=vetex[k].next)
{
j=vetex[k].v;
if (!DFN[j])
{
tarjan(j);
if (LOW[j]<LOW[i])
LOW[i]=LOW[j];
}
else if (instack[j] && DFN[j]<LOW[i])
LOW[i]=DFN[j];
}
if (DFN[i]==LOW[i])
{
Bcnt++;
do
{
j=Stap[Stop--];
instack[j]=false;
Belong[j]=Bcnt;
}
while (j!=i);
}
}
void solve()
{
int i;
Stop=Bcnt=Dindex=0;
for (i=1;i<=N;i++)
if (!DFN[i])
tarjan(i);
}
int main()
{
while(cin>>N)
{
k=1;
memset(in_num,0,sizeof(in_num));
memset(out_num,0,sizeof(out_num));
memset(DFN,0,sizeof(DFN));
memset(head,false,sizeof(head));
for(int i=1;i!=N+1;i++)
{
int a;cin>>a;
while(a!=0)
{
add(i,a);
cin>>a;
}
}
solve();
if(Bcnt == 1)
{
cout<<1<<endl;
cout<<0<<endl;
continue;
}
//cout<<Bcnt<<endl;
for(int i=1;i!=N+1;i++)
{
int t = Belong[i];
for(int k=head[i];k;k=vetex[k].next)
{
if(t!=Belong[vetex[k].v])
{
out_num[Belong[vetex[k].v]] = true;
in_num[t] = true;
}
}
}
int in(0),out(0);
for(int i=1;i!=Bcnt+1;i++)
{
if(!in_num[i])
{
in++;
}
if(!out_num[i])
{
out++;
}
}
cout<<out<<endl;
cout<<((in>out)?in:out)<<endl;
}
return 0;
}