http://poj.org/problem?id=2186
//poj2186 强联通图模板 节点数1W 边数5W 79ms G++
#include<stdio.h>
const int sz = 50000+10;
struct Edge
{
int to;
int next;
};
Edge edge[sz]; //存放边
int head[sz]={0};//每个节点的第一条边的编号
int n,m;//有n个节点,m条边
int cnt;//边的编号
int stack[sz];//栈
int top;
int dfn[sz]={0},low[sz]={0};//targin要用的变量
bool instack[sz]={false};//是否存在栈中
int c = 0;//递增量 ,时间戳
int sc = 0 ;//一共有多少个联通分量
int count[sz]={0};//每个联通分量有多少个节点
int min(int a,int b)
{
return a<b?a:b;
}
void targin(int u)
{
low[u]=dfn[u]=++c; //时间戳
// s.push(u);
stack[top++] = u;//入栈
instack[u]=true;
for(int i=head[u];i;i=edge[i].next)
{
int v = edge[i].to;
if(dfn[v]==0) targin(v);
if(instack[v])low[u] = min(low[u],low[v]);
}
if(dfn[u]==low[u])
{
sc++;
int v;
do
{
v = stack[--top];//出栈
instack[v]=false;//标记
count[sc]++;//这个联通分量的节点数加1
low[v] = sc;//记录节点v属于哪一个联通分量
}while(v!=u);
}
}
void addEdge(int u,int v)
{
edge[++cnt].next=head[u];
edge[cnt].to = v;
head[u] = cnt;
}
void solve()//输出结果
{
int out[sz]={0};
for(int i=1;i<=n;i++)
{
for(int j=head[i];j;j=edge[j].next)
{
if(low[i]!=low[edge[j].to])
{
out[low[i]]=1;
break;
}
}
}
int c = 0;
int id;
for(int i=1;i<=sc;i++)
{
if(out[i]==0) //如果出度为0
{
c ++ ;
if(c>1){
printf("0\n");
return ;
}
id = i;
}
}
printf("%d\n",count[id]);
}
void init()
{
sc = cnt = top = 0;
for(int i=1;i<=n;i++)
{
dfn[i]=low[i]=head[i]=count[i]=0;
instack[i]=false;
}
}
int main()
{
scanf("%d %d",&n,&m);
init();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d %d",&u,&v);
addEdge(u,v);
}
for(int i=1;i<=n;i++)//不联通
{
if(dfn[i]==0)
{
targin(i);
}
}
solve();
return 0;
}
强联通图缩点后:得到一个DAG(有向无环图),得到这个DAG我们可以处理一些问题:
1.问:是否存在某些点(point1或point2 。。。。。),使得 所有的点是否可以汇聚到这个点(point1 或 point2 。。。。。)上,比如3个点1 2 3 ,1-->2 2-->1 2-->3 画图可知 1 2 都可以汇聚到3上面,
问题可以转化为 一共有多少个出度为0 的强连通图 ,如果只有1个,则结果就是该连通图的节点数,如果>1 ,则没有。因为最终的DAG,如果有2个强联通图没有出度,
则必定有一个点 得不到另外一个点的汇聚。
2.问:有一个消息,如果A 到B右一条有向边A-->B,则A可以把消息传给B,问我们至少需要选择多少个点,作为信息的源点,最终可以使得每一个节点都获得该 消息
问题转化为: 一共有多少个节点没有入度,因为没有入度的点没有消息来源,我们需要选择它作为源点
3.问: 我们至少需要添加多少条有向边,才可以使得整个图为强联通图
问题转化为: 计算得到 入度为0的强联通图个数 in0 , 计算得到出度为0的强联通图的个数 out0,然后结果就是max(in0,out0)。因为强联通图必然是每个点都有出度和入度,
所以我们必须为没有入度或者出度的点 连边,那么最少就需要max(in0,out0)条边。