想看更多的解题报告:http://blog.csdn.net/wangjian8006/article/details/7870410
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:如果v点能够到的点,反过来能够到达v点,则称这个点为sink点,输出所有的sink点
解题思路:求连通分量,然后出度为0的连通分量里面的点就是sink点
/* kosaraju Memory 524K Time 63MS */ #include <iostream> using namespace std; #define MAXM 50010 #define MAXV 5010 #define min(a,b) (a>b?b:a) typedef struct{ int s,t,next,next2; }Edge; Edge edge[MAXM]; int n,m,headlist[MAXV],headlist2[MAXV]; int order[MAXV],belong[MAXV]; int num,count; bool vis[MAXV]; void dfs(int x){ int i,a; vis[x]=1; for(i=headlist[x];i!=-1;i=edge[i].next){ a=edge[i].t; if(!vis[a]) dfs(a); } order[++num]=x; } void dfst(int x){ int i,a; belong[x]=count; //记录结点属于哪个连通分量 vis[x]=1; for(i=headlist2[x];i!=-1;i=edge[i].next2){ //要将边反过来遍历一遍 a=edge[i].s; if(!vis[a]) dfst(a); } } void kosaraju(){ int i; memset(vis,0,sizeof(vis)); num=count=0; for(i=1;i<=n;i++) if(!vis[i]) dfs(i); memset(vis,0,sizeof(vis)); for(i=n;i>=1;i--) if(!vis[order[i]]){ count++; dfst(order[i]); } } void output(){ int i,j,outdegree[MAXV]={0}; for(i=1;i<=n;i++) for(j=headlist[i];j!=-1;j=edge[j].next) if(belong[i]!=belong[edge[j].t]){ outdegree[belong[i]]++; } memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) if(!outdegree[belong[i]]) vis[i]=1; for(i=1;i<=n;i++) if(vis[i]) printf("%d ",i); printf("\n"); } int main(){ int i,a,b; while(scanf("%d",&n) && n){ memset(headlist,-1,sizeof(headlist)); memset(headlist2,-1,sizeof(headlist2)); scanf("%d",&m); for(i=0;i<m;i++){ scanf("%d%d",&a,&b); edge[i].s=a; edge[i].t=b; edge[i].next=headlist[a]; headlist[a]=i; edge[i].next2=headlist2[b]; //记录反边 headlist2[b]=i; } kosaraju(); output(); } return 0; }
====================================================================
/* tarjan Memory 544K Time 63MS */ #include <iostream> using namespace std; #define MAXM 50010 #define MAXV 10010 #define min(a,b) (a>b?b:a) typedef struct{ int s,t,next; }Edge; Edge edge[MAXM]; int n,m,headlist[MAXV]; int dfn[MAXV]; //第一次访问的步数 int low[MAXV]; //子树中最早的步数 int stap[MAXV],stop; //模拟栈 bool instack[MAXV]; //是否在栈中 int count; //记录连通分量的个数 int cnt; //记录搜索步数 int belong[MAXV]; //属于哪个连通分量 void init(){ count=stop=cnt=0; memset(instack,false,sizeof(instack)); memset(dfn,0,sizeof(dfn)); } void tarjan(int x){ int i; dfn[x]=low[x]=++cnt; stap[stop++]=x; instack[x]=true; for(i=headlist[x];i!=-1;i=edge[i].next){ int a=edge[i].t; if(!dfn[a]){ tarjan(a); low[x]=min(low[a],low[x]); }else if(instack[a]) low[x]=min(dfn[a],low[x]); } if(low[x]==dfn[x]){ count++; while(1){ int tmp=stap[--stop]; belong[tmp]=count; instack[tmp]=false; if(tmp==x) break; } } } void work(){ init(); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); } void output(){ int i,j,outdegree[MAXV]={0}; for(i=1;i<=n;i++) for(j=headlist[i];j!=-1;j=edge[j].next) if(belong[i]!=belong[edge[j].t]){ outdegree[belong[i]]++; } memset(instack,0,sizeof(instack)); for(i=1;i<=n;i++) if(!outdegree[belong[i]]) instack[i]=1; for(i=1;i<=n;i++) if(instack[i]) printf("%d ",i); printf("\n"); } int main(){ int i,a,b; while(~scanf("%d%d",&n,&m)){ memset(headlist,-1,sizeof(headlist)); for(i=0;i<m;i++){ scanf("%d%d",&a,&b); edge[i].s=a; edge[i].t=b; edge[i].next=headlist[a]; headlist[a]=i; } work(); output(); } return 0; }