POJ1236 - Network of Schools - 强连通分量求缩点 - Tarjan模板题
题意
要求我们输出:
1、至少给几个点传递消息,才能保证所有消息传遍整个图;
2、至少添加几条边,才能使任意选择一个点,消息都能传遍整个图。
思路
强连通模板题。
第一问:强连通分量缩点之后有几个入度为0的点。
第二问:首先我们画个图,就能发现只要把入度为0的点直接连一条边到入度为0的点上,就可以形成一个环,所以答案是:max(入度为0的点,出度为0的点)。
3、注意一下特判,如果SCC只有一个,输出0即可。
AC代码
#include<stdio.h>
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int N=110;
int n,m,tot,num,countt,top,head[10*N];
int in[N],out[N],low[N],dfn[N],co[N],st[N],si[N];
bool book[N][N];
struct node
{
int nextt,v;
} e[N*N*10];
void add(int u,int v)
{
tot++;
e[tot].nextt=head[u];
head[u]=tot;
e[tot].v=v;
}
void tarjan(int u)
{
//top=0;
dfn[u]=low[u]=++num;
st[++top]=u;//入栈
for(int i=head[u]; i!=-1; i=e[i].nextt)
{
int v=e[i].v;
if(dfn[v]==0)
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(co[v]==0)
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
co[u]=++countt;//countt是连通分量个数
++si[countt];
while(st[top]!=u)
{
++si[countt];
co[st[top--]]=countt;
}
--top;//出栈
}
}
void init()
{
countt=num=top=0,tot=-1;
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(co,0,sizeof(co));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(book,0,sizeof(book));
}
int main()
{
while(~scanf("%d",&n))
{
init();
for(int i=1; i<=n; i++)
{
while(1)
{
int x;
scanf("%d",&x);
if(x==0)
break;
add(i,x);
book[i][x]=1;
}
}
for(int i=1; i<=n; i++)
{
if(dfn[i]==0)
tarjan(i);
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(book[i][j]&&(co[i]!=co[j]))//说明点i可以到j&&i和j不在同一个连通分量里面
{
out[co[i]]++;
in[co[j]]++;
}
}
}
int inn=0,outt=0;
for(int i=1; i<=countt; i++)
{
if(out[i]==0)
outt++;
if(in[i]==0)
inn++;
}
if(countt==1)//特判
{
printf("1\n");
printf("0\n");
}
else
{
//至少给几个点传递消息,才能保证所有消息传遍整个图
printf("%d\n",inn);//输出入度为0的个数
//至少添加几条边,才能使任意选择一个点,消息都能传遍整个图
int ans=max(outt,inn);//输出入度为0和出度为0的max
printf("%d\n",ans);
}
}
return 0;
}