题意:求在图上可以被所有点到达的点的数量。
首先通过tarjan缩点,将所有内部两两可达的子图缩为一点,新图即为一个有向无环图(即DAG)。
在这个DAG上,若存在不止一个所有点均可到达的点,则所有点不满足题目要求。若存在一个,则该点所代表的连通分量的点数即为答案。
//DAG(有向无环图)上面至少存在一个出度为0的点,否则必然可以成环。
#include<cstdio> #include<cstring> #include<stack> #include<vector> using namespace std; typedef long long LL; ; int n,m; int idd; //用来给点标记所属连通分量 int cnt[N]; //cnt[idd]表示编号为idd的连通分量的大小 int id[N]; //记录所属的连通分量 int now,dfn[N]; //表示搜索次序 int low[N]; //记录强连通分量子树的根节点的搜索次序 int d[N]; //d[i]==0时表示,编号为i的连通分量不认为任何其他分量popular int vis[N],instack[N]; vector<int> adj[N]; stack<int> st; void init() { idd=; memset(vis,,sizeof(vis)); memset(d,,sizeof(d)); ; i<=n; i++) adj[i].clear(); while(!st.empty()) st.pop(); now=; //now 表示 tarjan次序 } void tarjan(int u) { dfn[u]=low[u]=now++; //标记被访问时间 vis[u]=instack[u]=; st.push(u); ; i<adj[u].size(); i++) { int x=adj[u][i]; //x表示下一个 if(!vis[x]) { tarjan(x); low[u]=min(low[u],low[x]); } else if(instack[x]) low[u]=min(low[u],dfn[x]); //注意两个min的区别 } if(dfn[u]==low[u]) //u结点为根节点 { ,res=; while(!st.empty()&&nowp!=u) { nowp=st.top(),st.pop(); instack[nowp]=; id[nowp]=idd; res++; } cnt[idd++]=res; //将连通分量的点数记录下来 } } int main() { while(~scanf("%d%d",&n,&m)) { init(); ; i<m; i++) { int u,v; scanf("%d%d",&u,&v); adj[v].push_back(u); } ; i<=n; i++) //强连通分量缩点 if(!vis[i]) tarjan(i); ; i<=n; i++) ; j<adj[i].size(); j++) if(id[i]!=id[adj[i][j]]) d[id[adj[i][j]]]++; ; ; i<idd; i++) if(!d[i]) res++; ) ; i<idd; i++) { ) { printf("%d\n",cnt[i]); break; } } else puts("); } }