poj 2553 强连通

来源:互联网 发布:office2016 for mac卡 编辑:程序博客网 时间:2024/05/16 10:23

题意:给出一个有向图,定义:若节点v所有能到达的点{wi},都能反过来到达v,那么称节点v是sink。题目要求所有的sink点。

 

思路:强连通缩点找出出度为零的点,输出即可。

 

这题主要问题是读题,了解题意之后就好做了,然后在数组开小了导致WA?挺莫名其妙的。。

 

代码:

#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>using namespace std;#define MAXN 10500#define MAXM 20000000struct Edge{      int v, next;}edge[MAXM];    //边结点数组int first[MAXN], stack[MAXN], DFN[MAXN], Low[MAXN], Belong[MAXN];int indegree[MAXN],outdegree[MAXN];// first[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,Belong[]为每个结点所对应的强连通分量标号数组// Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号int instack[MAXN];  // instack[]为是否在栈中的标记数组int n, m, cnt, scnt, top, tot;void init(){    cnt = 0;    scnt = top = tot = 0;    //初始化连通分量标号,次序计数器,栈顶指针为0    for(int i=0;i<=n+100;i++)    {        first[i]=-1;        outdegree[i]=0;        DFN[i]=0;    }}void read_graph(int u, int v) //构建邻接表{     edge[tot].v = v;     edge[tot].next = first[u];     first[u] = tot++;}void Tarjan(int v)       //Tarjan算法求有向图的强连通分量{     int min, t;     DFN[v] = Low[v] = ++tot;    //cnt为时间戳     instack[v] = 1;    //标记在栈中     stack[top++] = v;      //入栈     for(int e = first[v]; e != -1; e = edge[e].next)     {   //枚举v的每一条边           int j = edge[e].v;   //v所邻接的边           if(!DFN[j])           {   //未被访问               Tarjan(j);    //继续向下找               if(Low[v] > Low[j]) Low[v] = Low[j];  // 更新结点v所能到达的最小次数层           }           else if(instack[j] && DFN[j] < Low[v])           {   //如果j结点在栈内,               Low[v] = DFN[j];           }     }     if(DFN[v] == Low[v])     {     //如果节点v是强连通分量的根           scnt++;   //连通分量标号加1           do           {               t = stack[--top];   //退栈               instack[t] = 0;   //标记不在栈中               Belong[t] = scnt;   //出栈结点t属于cnt标号的强连通分量           }while(t != v);  //直到将v从栈中退出     }}void solve(){     for(int i = 1; i <= n; i++)   //枚举每个结点,搜索连通分量        if(!DFN[i])  //未被访问           Tarjan(i);  //则找i结点的连通分量}int e1[MAXN];int e2[MAXN];int main(){    while(scanf("%d",&n),n)    {        init();        scanf("%d",&m);        for(int i=1;i<=m;i++)        {            int v,w;            scanf("%d%d",&v,&w);            e1[tot]=v;            e2[tot]=w;            read_graph(v, w);        }        int num=tot;        solve();     //求强连通分量        for(int i=0;i<num;i++)        {            if(Belong[e1[i]]!=Belong[e2[i]])                outdegree[Belong[e1[i]]]++;        }        bool ff=false;        for(int i=1;i<=n;i++)        {            if(!outdegree[Belong[i]])            {                if(ff==false)                {                    printf("%d",i);                    ff=true;                }                else                {                    printf(" %d",i);                }            }        }        printf("\n");    }    return 0;}