POJ 2186
这是一道Tarjan算法求强连通分量的题。方法是将强连通分量缩为一个点集,找出出度为0的点(或点集),值得注意的是,答案是存在于1个点集之内,如果存在两个点集合,那么它们就是互相可达的,于是又属于一个强连通分量,所以也应该缩为一个点集。
由于数据量比较大,内存有限制,所以使用邻接表而不是邻接矩阵。由于以前觉得邻接矩阵比邻接表好写,所以对于邻接表只是略微的了解了一下,这次是第一次写邻接表,所以走了许多弯路:在节点的遍历上,我专门写了一个函数来判断两个节点之间有没有路,由于tarjan函数和求出度的时候都会用到,所以大量的函数调用造成了TLE;对于head数组,开始开的是一维,所以又写了一个函数来找到表尾,后来决定用空间换时间,多开一维,存下邻接表的末尾的节点。
#include<stdio.h> #include<string.h> #include<stdbool.h> #define MAX_COW 10010 struct node { int vertex; int next; }edge[MAX_COW*4]; void tarjan(int,int),add(int,int); inline int get_min(int,int); bool instack[MAX_COW]; int dfn[MAX_COW],stack[MAX_COW],belong[MAX_COW],out[MAX_COW],containNum[MAX_COW]; int low[MAX_COW],head[2][MAX_COW]; int indx=0,set=0,top=0,cntVertex=0; int main() { int m,n; while(scanf("%d%d",&n,&m)!=EOF) { int i; for(i=0;i<=n;i++) { head[0][i]=head[1][i]=0; out[i]=containNum[i]=0; dfn[i]=-1; } indx=top=0; cntVertex=set=1; for(i=0;i<m;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); } for(i=1;i<=n;i++) { if(dfn[i]==-1) tarjan(i,n); } int j; for(i=1;i<=n;i++) { j=head[0][i]; while(j!=0) { int now=edge[j].vertex; if(belong[i]!=belong[now]) { out[belong[i]]++; } j=edge[j].next; } } int ans=0,flag=0; for(i=1;i<set;i++) { if(out[i]==0) { ans+=containNum[i]; flag++; if(flag>1) break; } } if(flag>1) printf("0\n"); else printf("%d\n",ans); } return 0; } void tarjan(int dest,int n) { dfn[dest]=low[dest]=indx++; stack[top++]=dest; instack[dest]=1; int i=head[0][dest]; while(i!=0) { int now=edge[i].vertex; if(dfn[now]==-1) { tarjan(now,n); low[dest]=get_min(low[dest],low[now]); } else if(instack[now]) { low[dest]=get_min(low[dest],dfn[now]); } i=edge[i].next; } if(low[dest]==dfn[dest]) { while(1) { int nowNode=stack[--top]; belong[nowNode]=set; containNum[set]++; instack[nowNode]=0; if(nowNode==dest) break; } set++; } } inline int get_min(int x,int y) { return x<y?x:y; } void add(int from,int to) { struct node tmp={to,0}; if(head[1][from]==0) { head[0][from]=cntVertex; head[1][from]=cntVertex; edge[cntVertex++]=tmp; return ; } else { int dest=head[1][from]; edge[dest].next=cntVertex; head[1][from]=cntVertex; edge[cntVertex++]=tmp; } }