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)条边。