题意:此题最难的部分即是理解题意。
注意要求得点的定义为:所有这个点能到达的点都能到达这个点。
思路:
强连通,缩点,找出出度为0的强连通分量集合,就是要求得点集合。
#include<iostream> #define min(a,b) (a<b?a:b) using namespace std; const int N=5005; bool mat[N][N]; int dfn[N],low[N]; bool instack[N]; int indgr[N]; int outdgr[N]; int stack[N]; int sp; int index; int n,m; int belong[N]; void tarjan(int i) { dfn[i]=low[i]=index++; stack[sp++]=i; instack[i]=true; for(int j=1;j<=n;j++) { if(mat[i][j]) { if(!dfn[j]) { tarjan(j); low[i]=min(low[i],low[j]); } else if(instack[j]) { low[i]=min(dfn[j],low[i]); } } } if(low[i]==dfn[i]) { int j; do { j=stack[--sp]; instack[j]=false; belong[j]=i; }while(j!=i); } } void solve() { for(int i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(mat[i][j]) { if(belong[i]!=belong[j]) { indgr[belong[j]]++; outdgr[belong[i]]++; } } } for(int i=1;i<=n;i++) { if(outdgr[belong[i]]==0) { printf("%d ",i); } } printf("\n"); } int main() { while(scanf("%d%d",&n,&m),n!=0) { index=1; sp=1; memset(indgr,0,sizeof(indgr)); memset(outdgr,0,sizeof(outdgr)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(mat,0,sizeof(mat)); memset(instack,0,sizeof(instack)); memset(stack,0,sizeof(stack)); memset(belong,0,sizeof(belong)); int from,to; for(int i=1;i<=m;i++) { scanf("%d%d",&from,&to); mat[from][to]=true; } solve(); } return 0; }