pku 1236 Network of Schools (tarjan缩点)
http://poj.org/problem?id=1236
N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
首先求出该图所有的强连通分量,将其缩为一点,因为对于强连通分量,任意两点都能互相可达,只要给DAG(强连通分量)中的任意一点都能互相到达。
缩点后然后统计每个点的入度与出度,入度为0的点肯定是A的答案,而对于答案B则是max(入度为0的点的个数,出度为0的点的个数)。B:入度为0我们只有给他一条路线入度+1能获得软件,出度同理。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 107
using namespace std;
struct node
{
int v;
int next;
}g[maxn*maxn];
int low[maxn],dfn[maxn],head[maxn],stack[maxn],belong[maxn];
int in[maxn],out[maxn];
bool instack[maxn];
int bcnt,index,t,top,n;
void init()
{
memset(g,0,sizeof(g));
for (int i = 0; i < maxn; ++i)
{
head[i] = low[i] = dfn[i] =stack[i] = in[i] = out[i] = 0;
belong[i] = 0;
instack[i] = false;
}
t = 1;
index = bcnt = top = 0;
}
void add(int u,int v)
{
g[t].v = v;
g[t].next = head[u];
head[u] = t++;
}
void tarjan(int i)
{
int j,k;
low[i] = dfn[i] = ++index;
instack[i] = true;
stack[++top] = i;
for (k = head[i]; k; k = g[k].next)
{
j =g[k].v;
if (!dfn[j])
{
tarjan(j);
low[i] = min(low[i],low[j]);
}
else if(instack[j])
{
low[i] = min(low[i],dfn[j]);
}
}
if (dfn[i] == low[i])
{
bcnt++;
do
{
j = stack[top--];
instack[j] = false;
belong[j] = bcnt;
}while (j != i);
}
}
void solve()
{
for (int i = 1; i <= n; ++i)
{
if (!dfn[i])
tarjan(i);
}
for (int i = 1; i <= n; ++i)
{
//printf("~!!!%d\n",belong[i]);
for (int j = head[i]; j; j = g[j].next)
{
int k = g[j].v;
if (belong[k] != belong[i])
{
out[belong[i]]++;
in[belong[k]]++;
}
}
}
int ct1 = 0;
int ct2 = 0;
for (int i = 1; i <= bcnt; ++i)//这里要小于bcnt因为这是缩点后的
{
if (!in[i]) ct1++;
if (!out[i]) ct2++;
}
printf("%d\n",ct1);
if (bcnt == 1) printf("0\n");
else
printf("%d\n",max(ct1,ct2));
}
int main()
{
//freopen("d.txt","r",stdin);
int i,x;
while (cin>>n)
{
init();
for (i = 1; i <= n; ++i)
{
while (cin>>x)
{
if (!x) break;
add(i,x);
}
}
solve();
}
return 0;
}