题意:有若干学校,某些学校可以达到其他学校。问题1:一个新软件要给予全部学校最少给多少个学校;问题2:将软件随机给学校,问较之问题1的最少数量需要增加多少条道路?
思路:tarjan求强连通分量,之后缩点形成有向无环图。有向无环图中所有入度不为0的点,一定可以由某个入度为0的点出发可达。 (由于无环,所以从任何入度不为0的点往回走,必然终止于一个入度为0的点)。问题一为此图入度为0的定点数。问题2为图中入度为0和出度为0的顶点数量的大者。
输入:
5
2 4 3 0
4 5 0
0
0
1 0
输出:
1
2
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define INF 0x3fffffff
#define N 105
struct edge{
int y,next;
}e[N*N*2];
int n,first[N],top,dfn[N],low[N];
int in[N],out[N],strong[N],stack[N],instack[N],con,id,ts;
void add(int x,int y){
e[top].y = y;
e[top].next = first[x];
first[x] = top++;
}
void tarjan(int x){
int i;
dfn[x] = low[x] = ++id;
stack[ts++] = x;
instack[x] = 1;
for(i = first[x];i!=-1;i=e[i].next){
if(dfn[e[i].y] == -1){
tarjan(e[i].y);
low[x] = min(low[x],low[e[i].y]);
}else if(instack[e[i].y])
low[x] = min(low[x],dfn[e[i].y]);
}
if(dfn[x] == low[x]){
con++;
do{
strong[stack[--ts]] = con;
instack[stack[ts]] = 0;
}while(x!=stack[ts]);
}
}
int main(){
int i,j,res1,res2;
scanf("%d",&n);
top = id = con = ts = res1 = res2 = 0;
memset(first, -1, sizeof(first));
memset(dfn, -1, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(instack, 0, sizeof(instack));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
for(i = 1;i<=n;i++)
while(scanf("%d",&j) && j)
add(i,j);
for(i = 1;i<=n;i++)
if(dfn[i] == -1)
tarjan(i);
if(con == 1){//只有一个强连通分量时候要特判!!!!!!
printf("1\n0\n");
return 0;
}
for(i = 1;i<=n;i++)
for(j = first[i];j!=-1;j=e[j].next)
if(strong[i] != strong[e[j].y]){
out[strong[i]]++;
in[strong[e[j].y]]++;
}
for(i = 1;i<=con;i++){
if(!in[i])
res1++;
if(!out[i])
res2++;
}
printf("%d\n%d\n",res1,max(res1,res2));
return 0;
}