题意:给你一个有向图,问最少几个学校可以达到所有学校,然后又问,加多少边可以使得任意学校到达任意学校。
思路:把构成强连通的点们当作1个点处理,然后在“新图”中找到入度为0的点的个数和出度为0的点的个数。对于第一问,只要输出入度为0的点的个数即可。对于第二问,如果所以点构成1个强连通,那么不许要添加边,即输出0;否则输出max(入度为0的点的个数,出度为0的点的个数)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
struct Edge
{
int u,v;
}e[10005];
int n,d[105],dfn[105],low[105],recve,next[10005],fst[105],edgenum,scnum,num,in[105],out[105],innum,outnum;
bool instack[105];
stack<int>st;
void init()
{
edgenum=0;
scnum=0;
num=0;
innum=0;
outnum=0;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(instack,0,sizeof(instack));
memset(dfn,0,sizeof(dfn));
memset(fst,-1,sizeof(fst));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
while(scanf("%d",&recve)&&recve)
{
next[++edgenum]=fst[i];
fst[i]=edgenum;
e[edgenum].v=recve;
e[edgenum].u=i;
}
}
}
void tarjan(int u)
{
dfn[u]=low[u]=++num;
st.push(u);
instack[u]=1;
for(int i=fst[u];i!=-1;i=next[i])
{
int v=e[i].v;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
int v;
scnum++;
do
{
v=st.top();
st.pop();
instack[v]=0;
d[v]=scnum;
}while(v!=u);
}
}
void strongconnect()
{
for(int i=1;i<=n;i++)
{
if(!dfn[i])tarjan(i);
}
}
void solve()
{
for(int i=1;i<=n;i++)
{
for(int j=fst[i];j!=-1;j=next[j])
{
int v=e[j].v;
if(d[i]!=d[v])
{
in[d[v]]++;
out[d[i]]++;
}
}
}
for(int i=1;i<=scnum;i++)
{
if(in[i]==0)innum++;
if(out[i]==0)outnum++;
}
printf("%d\n",innum);
if(scnum==1)printf("0\n");
else printf("%d\n",max(innum,outnum));
}
int main()
{
init();
strongconnect();
solve();
return 0;
}