hoj 2741 The Busiest Man // 强连通分支+缩点+传递闭包

/*



题目:

    有n种物品,现给出m种关系,每种关系a,b对应着物品b能够用物品a来换,然后有q个询问(a,b),

    问物品a能不能换到物品b。



分析:

    如果直接dfs求传递闭包的话,会超时的。我们可以重新建图,使得图中没有环,即把强连通分支

    变成缩点后用邻接表重新建图,然后dfs求传递闭包即可



*/

#include <cstdio>

#include <vector>

#include <cstring>

#include <iostream>



using namespace std;



const int X = 5005;



int dfn[X],father[X],low[X],stack[X],depth,top,bcnt;

int n,m,t;

bool instack[X];

bool map[1005][1005];   //新图中的关系

vector<int> adj[X];     //旧图

vector<int> nadj[X];    //新图



void tarjan(int u)  //tarjan算法求强连通分支

{

    int len,v;

    low[u] = dfn[u] = ++depth;

    stack[++top] = u;

    instack[u] = true;

    len = adj[u].size();

    for(int i=0;i<len;i++)

    {

        v = adj[u][i];

        if(!low[v])

        {

            tarjan(v);

            low[u] = min(low[u],low[v]);

        }

        else if(instack[v])

            low[u] = min(low[u],dfn[v]);

    }

    if(low[u]==dfn[u])

    {

        ++bcnt;

        do

        {

            v = stack[top--];

            instack[v] = false;

            father[v] = bcnt;

        }while(u!=v);

    }

}



void solve()

{

    depth = top = bcnt = 0;

    memset(instack,false,sizeof(instack));

    memset(low,0,sizeof(low));

    memset(map,false,sizeof(map));



    for(int i=1;i<=n;i++)

        if(!low[i])

            tarjan(i);

    int len,v;

    for(int u=1;u<=n;u++)   //重新建图

    {

        len = adj[u].size();

        for(int j=0;j<len;j++)

        {

            v = adj[u][j];

            if(father[u]!=father[v])//father记录的是在新图中的顶点号(所在缩点的号码)

                nadj[father[u]].push_back(father[v]);

        }

    }

}



void dfs(int u,int v)   //dfs求传递闭包,若用floyd的话会超时

{

    int len = nadj[v].size();

    for(int i=0;i<len;i++)

        dfs(u,nadj[v][i]);

    map[u][v] = true;

}



int main()

{

    freopen("sum.in","r",stdin);

    freopen("sum.out","w",stdout);

    int u,v;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(int i=1;i<=n;i++)   //初始化

        {

            adj[i].clear();

            nadj[i].clear();

        }

        for(int i=0;i<m;i++)

        {

            scanf("%d%d",&u,&v);

            adj[u].push_back(v);

        }

        solve();

        for(int i=1;i<=bcnt;i++)    //求传递闭包

            dfs(i,i);



        scanf("%d",&t);

        while(t--)

        {

            scanf("%d%d",&u,&v);

            if(father[u]==father[v])

            {

                printf("Yes\n");

                continue;

            }

            if(map[father[u]][father[v]])

                printf("Yes\n");

            else

                printf("No\n");

        }

    }

    return 0;

}

 

你可能感兴趣的:(man)