题目大意:一些学校间需要共享软件,而学校之间只有单向通信网络。
【问题一】:求发放最小的软件数使所有学校能共享到软件(思路:找出所有强连通,缩点(不用建立新图),数出入度为0的子图数即可)
【问题二】:求添加最少的通信路使给任何一个学校发放软件,其他学校都能共享到(思路:找出所有强连通子图后,求出入度和出度为0的个数,则构建强连通图所需要的数量就是强连通子图数减去min(入度为0的数,出度为0的数),证明略;
Source Code
Problem: 1236 User: nd096040177
Memory: 264K Time: 0MS
Language: C++ Result: Accepted
Source Code
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
#define MyMax 1000
struct Node
{
int dest;
struct Node *next;
}node[101];
stack<int>Q;
int N;
struct Node *p;
int node_class[101];//代表所属强连通子图
int dfn[101],low[101];//代表深搜的节点数和自身及子孙能到达的最低dfn数(即越先访问的节点)
bool in[101],out[101];//代表该强连通子图是否有入度与出度
bool IsVisit[101],IsInStack[101];//代表该点是否已经访问过
int NowCount,nodeClass_num,inNum,outNum;
void addNode(int ti,int tdest)//添加新节点,建立图。
{
p=new struct Node;
p->dest=tdest;
p->next=node[ti].next;
node[ti].next=p;
}
void init()//初始化
{
NowCount=0;//时间戳
nodeClass_num=0;//强连通子图标记
int i,tx;
for(i=1;i<=N;i++)//清空图
node[i].next=NULL;
memset(in,false,sizeof(in));
memset(out,false,sizeof(out));
memset(node_class,0,sizeof(node_class));
memset(IsVisit,false,sizeof(IsVisit));
memset(IsInStack,false,sizeof(IsInStack));
for(i=1;i<=N;i++)
{
scanf("%d",&tx);
while(tx!=0)
{
addNode(i,tx);
scanf("%d",&tx);
}
}
}
int min(int tx,int ty)
{
if(tx>ty) return ty;
else return tx;
}
void Tarjan(int ti)
{
int x;
dfn[ti]=low[ti]=++NowCount;
Q.push(ti);
IsInStack[ti]=IsVisit[ti]=true;
struct Node *q;
for(q=node[ti].next;q!=NULL;q=q->next)
{
x=q->dest;
if(!IsVisit[x])
{
Tarjan(x);
low[ti]=min(low[ti],low[x]);
}
else if(IsInStack[x])
{
low[ti]=min(low[ti],dfn[x]);
}
}
if(low[ti]==dfn[ti])
{
nodeClass_num++;
do
{
x=Q.top();
node_class[x]=nodeClass_num;
Q.pop();
IsInStack[x]=false;
}while(x!=ti);
}
}
void doit()
{
int i;
for(i=1;i<=N;i++)
{
if(!IsVisit[i])
Tarjan(i);
}
memset(IsVisit,false,sizeof(IsVisit));
//记录强连通子图是否有入度和出度
int t,r;
for(i=1;i<=N;i++)
{
for(p=node[i].next;p!=NULL;p=p->next)
{
t=node_class[i];
r=node_class[p->dest];
if(t!=r)
{
out[t]=true;
in[r
]=true;
}
}
}
inNum=outNum=0;
for(i=1;i<=nodeClass_num;i++)
{
if(in[i])
inNum++;
if(out[i])
outNum++;
}
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
init();
doit();
printf("%d\n",nodeClass_num-inNum);//输出入度为0的强连通子图数
if(nodeClass_num==1) printf("0\n");
else
{
if(inNum>outNum)
printf("%d\n",nodeClass_num-outNum);
else
printf("%d\n",nodeClass_num-inNum);
}
}
return 0;
}