题意:有n(2 <= n <= 100)所学校,一个学校可以给另一个学校发送软件,软件可以传递a->b->c这样只要a学校安装了软件,那么b,c学校也就可以通过a安装软件,先在告诉你个学校之间的关系,第一个问题,问需要最少给多少个学校安装软件所有的学校就都能装上软件了,第二个问题,问添加最少多少个关系可以使得一个学校安装软件所有学校就都能安装上软件了。
想法:如果有一个组学校,他们之间可以相互发送要安装的软件,那么显然不管是谁先安装这个组里的其它学校都能够安装。所以可以使用强连通算法进行缩点,在缩完点之后,可以想到给入度为0的几组组学校发送安装软件那么其它的学校也就必然可以安装了。对于第二个问题,实际上就是,添加最少的边使得原图变为一个强连通图,对于学校组A->B->C->D,我只要将加上D->A这一条边那么A,B,C,D组学校就变成强连通分量了。所以我可以只关心出度为0的连通分量向入度为0的连通分量加一条边即可。比如A->B, A->C, D现在有这四个连通分量可以增加边B->D->A,C->A共三条边。所以增加的边的个数是出度为0的点的数量和入度为0的点的数量中的最大值。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<stack>
using namespace std;
int N;
bool vis[105];
stack<int>s;
int paint[105];
int col;
struct Edge{//边
int v;
int w;
struct Edge *next;
};
struct FirstNode{//起始点
struct Edge *fstedge;
};
class AdjList{
public:
FirstNode *adjlist;
public:
AdjList(int num);
~AdjList()
{
delete[] adjlist;
}
void _init();
void AddEdge(int u, int v, int w);
void AddEdge(int u, int v);
private:
int num_node;//图中点的数量
};
AdjList G_1(100);
AdjList G_2(100);
AdjList::AdjList(int num)
{
num_node = num;
FirstNode *temp_adjlist = new FirstNode[num_node + 1];
adjlist = temp_adjlist;
temp_adjlist = NULL;
delete[] temp_adjlist;
}
void AdjList::_init()
{
for(int i = 1; i <= num_node; i++)
{
adjlist[i].fstedge = NULL;
}
}
void AdjList::AddEdge(int u, int v, int w)
{
struct Edge *newEdge;
newEdge = (Edge*)malloc(sizeof(Edge));
newEdge->v = v;
newEdge->w = w;
newEdge->next = adjlist[u].fstedge;
adjlist[u].fstedge = newEdge;
}
void AdjList::AddEdge(int u, int v)
{
struct Edge *newEdge;
newEdge = (Edge*)malloc(sizeof(Edge));
newEdge->v = v;
newEdge->next = adjlist[u].fstedge;
adjlist[u].fstedge = newEdge;
}
void dfs_1(int u)
{
vis[u] = true;
for(Edge *p = G_1.adjlist[u].fstedge; p != NULL; p = p->next)
{
int v = p->v;
if(!vis[v])
{
dfs_1(v);
}
}
s.push(u);
}
void dfs_2(int u)
{
vis[u] = true;
for(Edge *p = G_2.adjlist[u].fstedge; p != NULL; p = p->next)
{
int v = p->v;
if(!vis[v])
{
paint[v] = col;
dfs_2(v);
}
}
}
int get_max(int x, int y)
{
if(x > y) return x;
else return y;
}
void Get_Ans()
{
int fst_ans = 0;
int sec_ans = 0;
int indegree[105];
int outdegree[105];
memset(indegree, 0, sizeof(indegree));
memset(outdegree, 0, sizeof(outdegree));
for(int i = 1; i <= N; i++)
{
int u = i;
for(Edge *p = G_1.adjlist[u].fstedge; p != NULL; p = p->next)
{
int v = p->v;
if(paint[u] != paint[v])
{
++indegree[paint[v]];
++outdegree[paint[u]];
}
}
}
for(int i = 1; i <= col; i++)
{
if(indegree[i] == 0) ++fst_ans;
if(outdegree[i] == 0) ++sec_ans;
}
cout<<fst_ans<<endl<<get_max(fst_ans, sec_ans)<<endl;
}
int main()
{
while(cin>>N)
{
G_1._init();
G_2._init();
for(int i = 1; i <= N; i++)
{
while(true)
{
int k;
cin>>k;
if(k == 0) break;
G_1.AddEdge(i, k);
G_2.AddEdge(k, i);
}
}
col = 0;
memset(paint, 0, sizeof(paint));
memset(vis, false, sizeof(vis));
while(!s.empty()) s.pop();
for(int i = 1; i <= N; i++)
{
if(!vis[i])
{
dfs_1(i);
}
}
memset(vis, false, sizeof(vis));
while(!s.empty())
{
int u = s.top();
s.pop();
if(!vis[u])
{
++col;
paint[u] = col;
dfs_2(u);
}
}
if(col == 1) cout<<"1"<<endl<<"0"<<endl;
else Get_Ans();
}
return 0;
}