【题意】
N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
【题解】
找强连通分量,缩点。记f[i]为缩完点后的新图中各点入度,g[i]为出度,ans1为f[i]==0的点的数目,ans2为g[i]==0的点的数目则第一问为ans1,第二问则为max{ans1,ans2}。
至于第二问的解释,我的想法是对于得到的DAG图,考虑其中的出度为0的点和入度为0的点组成的点集V,将这些点相连,最多这需要max{ans1,ans2}条边,就能使整个图成为强连通分量。
但是请注意,大家可能都没发现,这个结论的前提是DAG图是连通的情况下才成立。如果DAG图有多个连通分量,则还要考虑将多个连通分量合并的所需代价。幸运的是,这道题保证了只有一个连通分量。(题目第一句话所说)
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=105;
const int maxe=105*105;
struct edge
{
int x,y,next;
}e[maxe];
int g[maxn],dfn[maxn],low[maxn],v[maxn],f[maxn],s[maxn],b[maxn],h[maxn];
int n,tot=0,cnt=0,ans=0,times=0,t=0,ans2;
void ins(int x,int y)
{
e[++tot].x=x;e[tot].y=y;
e[tot].next=h[x];h[x]=tot;
}
void tarjan(int x)
{
int y,i;
times++;t++;
dfn[x]=low[x]=times;
v[x]=1;s[t]=x;
for (i=h[x];i;i=e[i].next)
{
y=e[i].y;
if (v[y]==0)
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
if (v[y]==1)
low[x]=min(low[x],dfn[y]);
}
if (dfn[x]==low[x])
{
cnt++;
do
{
y=s[t--];
b[y]=cnt;v[y]=2;
}while (y!=x);
}
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
int i,j;
cin >> n;
for (i=1;i<=n;i++)
{
cin >> j;
while (j)
{
ins(i,j);
cin >> j;
}
}
for (i=1;i<=n;i++)
if (v[i]==0)
tarjan(i);
if (cnt==1)
{
cout << 1 << endl << 0 << endl;
return 0;
}
for (i=1;i<=tot;i++)
if (b[e[i].x]!=b[e[i].y])
{
f[b[e[i].x]]++;
g[b[e[i].y]]++;
}
ans=0;
for (i=1;i<=cnt;i++)
if (g[i]==0) ans++;
cout << ans << endl;
ans2=0;
for (i=1;i<=cnt;i++)
if (f[i]==0) ans2++;
cout << max(ans,ans2)<< endl;
}