POJ 2553The Bottom of a Graph

来源:互联网 发布:子弹图纸尺寸图片编程 编辑:程序博客网 时间:2024/04/30 12:45

题意:

定义一个点所能到达的所有点都能到达这个点,那么该点就是一个sink点,现给你n个点m条边的有向图,问你图中有多少个sink点,并指出对应的点。

思路:

首先明白一点,强连通分量里的所有点都是相互可达的,里面的点和分量外面的点都是只有一方可达的,所有我们只要用Tarjan缩点,然后对于出度为0的强连通分量,里面的所有点就是我们所求的点。

#include<cstdio>#include<vector>#include<stack>#include<cstring>#include<queue>#include<algorithm>using namespace std;const int MAXN=5005;int n,m,time,cnt,dfn[MAXN],low[MAXN],id[MAXN],out[MAXN];bool vis[MAXN],use[MAXN][MAXN];vector<int> gr[MAXN],se[MAXN],ans;stack<int> s;void init(){for(int i=1;i<=n;i++){gr[i].clear();se[i].clear();}while(!s.empty()){s.pop();}ans.clear();memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(out,0,sizeof(out));memset(vis,false,sizeof(vis));memset(use,false,sizeof(use));time=0;cnt=0;}void Tarjan(int u){int v;vis[u]=true;dfn[u]=low[u]=++time;s.push(u);for(int i=0;i<gr[u].size();i++){v=gr[u][i];if(!dfn[v]){Tarjan(v);low[u]=min(low[u],low[v]);}else if(vis[v]){low[u]=min(low[u],dfn[v]);}}if(low[u]==dfn[u]){cnt++;while(!s.empty()){v=s.top();s.pop();vis[v]=false;se[cnt].push_back(v);id[v]=cnt;if(u==v) break;}}}int main(){while(~scanf("%d",&n),n){scanf("%d",&m);init();int u,v;for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);gr[u].push_back(v);}for(int i=1;i<=n;i++){if(!dfn[i]){Tarjan(i);}}for(int i=1;i<=n;i++){for(int j=0;j<gr[i].size();j++){int v=gr[i][j];if(use[id[i]][id[v]]==false&&id[i]!=id[v]){use[id[i]][id[v]]=true;out[id[i]]++;}}}for(int i=1;i<=cnt;i++){if(!out[i]){for(int j=0;j<se[i].size();j++){int v=se[i][j];ans.push_back(v);}}}sort(ans.begin(),ans.end());for(int i=0;i<ans.size();i++){if(i!=0) printf(" ");printf("%d",ans[i]);}printf("\n");}return 0;}


0 0
原创粉丝点击