现在的位置: 首页 > 综合 > 正文

poj2553 有向图缩点,强连通分量。

2014年07月06日 ⁄ 综合 ⁄ 共 1872字 ⁄ 字号 评论关闭
//求这样的sink点:它能达到的点,那个点必能达到他,即(G)={v∈V|任意w∈V:(v→w)推出(w→v)}
//我法:tarjan缩点后,遍历点,如果该点到达的点不在同一个强连通中,该点排除,而且该点所在的
//的强连通分支所有点都排除(开始因为这个跪WA!慎思!)
#include<iostream>   //143MS,
#include<vector>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
int n;int m;
const int MAX=5001;
vector<vector<int> >edges(MAX);
int visited[MAX];
int low[MAX];
int dfn[MAX];
int is_sink[MAX];          //统计出入度
int Strongly_connected_branch[MAX];  //并为一个强连通,标记为1.2.3...
int num;int times;
bool is_sink_all[MAX];
stack<int>s;
bool instack[MAX];
void tarjan(int u)
{
    low[u]=dfn[u]=times++;
    instack[u]=1;
    s.push(u);
    int len=edges[u].size();
    for(int i=0;i<len;i++)
    {
        int v=edges[u][i];
        if(visited[v]==0)          //小心细节!
        {
             visited[v]=1;
               tarjan(v);
            if(low[u]>low[v])low[u]=low[v];
        }
        else if(instack[v]&&low[u]>dfn[v])     //有向图,要问是否在栈中,后向边,V为U某个祖先
        {
            low[u]=dfn[v];
        }
    }
    if(dfn[u]==low[u])         //在一个SCC
    {
        num++;int temp;
         do
        {
             temp=s.top();
             instack[temp]=0;
            s.pop();
            Strongly_connected_branch[temp]=num;
        } while(temp!=u);
    }
}
void initialize()
{
    num=times=0;
    for(int i=0;i<=n;i++)
    {
        instack[i]=low[i]=dfn[i]=visited[i]=0;
        edges[i].clear();
        is_sink_all[i]=is_sink[i]=1;
        Strongly_connected_branch[i]=-1;
    }
}
bool readin()
{
    scanf("%d",&n);
    if(n==0)return 0;
    scanf("%d",&m);
    initialize();
    int from,to;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&from,&to);
        edges[from].push_back(to);
    }
    return 1;
}
void solve()
{
    for(int i=1;i<=n;i++)
       if(visited[i]==0)
        {
            visited[i]=1;
            tarjan(i);
        }
     for(int i=1;i<=n;i++)     //自己思得:枚举所有边,缩点只是把所有SCC分开
   {                           
      int len=edges[i].size();
       for(int j=0;j<len;j++)
       {
          int v=edges[i][j];
          if(Strongly_connected_branch[v]!=Strongly_connected_branch[i])//b不再用一个强连通分支
          {
            is_sink[i]=0;          
            is_sink_all[Strongly_connected_branch[i]]=0; //其所在强连通全跪!
            break;
          }
       }
    }
    queue<int>q;       //要按顺序输出,无奈。
    for(int i=1;i<=n;i++)
    {
       if(is_sink_all[Strongly_connected_branch[i]]==0){continue;}
       if(is_sink[i]==1)q.push(i);
    }
    while(!q.empty())
    {
        int cur=q.front();
        if(q.size()==1)printf("%d\n",cur);
        else printf("%d ",cur);
        q.pop();
    }
}
int main()            //代码越来越清楚O(∩_∩)O~
{
   while(readin())
   {
       solve();
   }
   return 0;
}

抱歉!评论已关闭.