tarjan缩点

tarjan缩点_第1张图片原题地址

先缩点,然后找出出度为0的点,如果出度为0的点多于一个,说明没有牛能被其他的牛崇拜,否则输出该缩点所包含点的个数。

#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 1e5+5;
int n,m,dfn[N],low[N],belong[N],in[N],out[N],deep,reduce;
bool visit[N];
vector<int> component[N],g[N];
stack<int>s;
void init()
{
    deep=1;
    reduce=0;
    while(!s.empty()) s.pop();
    for(int i=1;i<=n;i++) component[i].clear(),g[i].clear();
    memset(visit,false, sizeof(visit));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}
void DFS(int u)
{
    int v,temp;
    s.push(u);
    visit[u]=true;
    dfn[u]=low[u]=deep++;
    for(int i=0;i<g[u].size();i++)
    {
        v=g[u][i];
        if(!dfn[v])
        {
            DFS(v);
            low[u]=min(low[u],low[v]);
        }
        else if(visit[v]&&low[u]>dfn[v]) low[u]=dfn[v];
    }
    if(low[u]==dfn[u])
    {
        reduce++;
        do
        {
            temp=s.top();
            visit[temp]=false;
            component[reduce].push_back(temp);
            belong[temp]=reduce;
            s.pop();
        }while(temp!=u);
    }
}
void Tarjan()
{
    for(int i=1; i<=n;++i)
        if(!dfn[i])
            DFS(i);
}
int Find()
{
    int sumout,ind;
    sumout=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<g[i].size();j++)
        {
            int v=g[i][j];
            if(belong[i]!=belong[v])
            {
                out[belong[i]]++;
                in[belong[v]]++;
            }
        }
    }
    for(int i=1;i<=reduce;++i)
    {
        if(out[i]==0)
        {
            sumout++;
            ind=i;
        }
    }
    if(sumout>1) return 0;
    else return component[ind].size();
}
int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        init();
        for(int i=1;i<=m;++i)
        {
            int begin,end;
            scanf("%d %d",&begin,&end);
            g[begin].push_back(end);
        }
        Tarjan();
        printf("%d\n",Find());
    }
    return 0;
}

tarjan缩点_第2张图片
原题地址
缩点之后,如果只剩一个点,那么不用添加边。否则找出出度为0的点和入度为0的点,输出两者中的最大值。

#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 20005;
int n,m,dfn[N],low[N],belong[N],in[N],out[N],deep,reduce;
bool vis[N];
vector<int> component[N],g[N];
stack<int> s;
void init()
{
    deep=1;
    reduce=0;
    while(!s.empty()) s.pop();
    for(int i=1;i<=n;i++) component[i].clear(),g[i].clear();
    memset(vis,false, sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}
void DFS(int u)
{
    int v,temp;
    s.push(u);
    vis[u]=true;
    dfn[u]=low[u]=deep++;
    for(int i=0;i<g[u].size();i++)
    {
        v=g[u][i];
        if(!dfn[v])
        {
            DFS(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v];
    }
    if(low[u]==dfn[u])
    {
        reduce++;
        do
        {
            temp=s.top();
            vis[temp]=false;
            component[reduce].push_back(temp);
            belong[temp]=reduce;
            s.pop();
        }while(temp!=u);
    }
}
void Tarjan()
{
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) DFS(i);
    }
}
int Find()
{
    if(reduce==1) return 0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<g[i].size();j++)
        {
            int v=g[i][j];
            if(belong[i]!=belong[v])
            {
                out[belong[i]]++;
                in[belong[v]]++;
            }
        }
    }
    int sumin=0,sumout=0;
    for(int i=1;i<=reduce;i++)
    {
        if(in[i]==0) sumin++;
        if(out[i]==0) sumout++;
    }
    return max(sumin,sumout);
}
int main()
{
    int loop;
    scanf("%d",&loop);
    while(loop--)
    {
        scanf("%d %d",&n,&m);
        init();
        for(int i=1;i<=m;i++)
        {
            int begin,end;
            scanf("%d %d",&begin,&end);
            g[begin].push_back(end);
        }
        Tarjan();
        printf("%d\n",Find());
    }
    return 0;
}

tarjan缩点_第3张图片
原题链接
当low[v]>=dfn[u]时,u为割点,其中v为u的子节点。

#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 20005;
int n,m,dfn[N],low[N],belong[N],in[N],out[N],iscut[N],deep,reduce;
bool vis[N];
vector<int> component[N],g[N];
stack<int> s;
void init()
{
    deep=1;
    reduce=0;
    while(!s.empty()) s.pop();
    for(int i=1;i<=n;i++) component[i].clear(),g[i].clear();
    memset(vis,false, sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}
int DFS(int u)
{
    int v,temp,cnt=0;
    s.push(u);
    vis[u]=true;
    dfn[u]=low[u]=deep++;
    for(int i=0;i<g[u].size();i++)
    {
        v=g[u][i];
        if(!dfn[v])
        {
            cnt++;
            DFS(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]) iscut[u]=1;
        }
        else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v];
    }
    if(low[u]==dfn[u])
    {
        reduce++;
        do
        {
            temp=s.top();
            vis[temp]=false;
            component[reduce].push_back(temp);
            belong[temp]=reduce;
            s.pop();
        }while(temp!=u);
    }
    return cnt;
}
void Tarjan()
{
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]&&DFS(i)==1)
        {
            iscut[i]=0;
        }
    }
}
int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            g[x].push_back(y);
            g[y].push_back(x);
        }
        Tarjan();
        int num=0;
        for(int i=1;i<=n;i++)
        {
            if(iscut[i]) num++;
        }
        printf("%d\n",num);
        for(int i=1;i<=n;i++)
        {
            if(iscut[i]) printf("%d ",i);
        }
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(tarjan缩点)