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;
}

 

posted @ 2012-05-19 10:45  yejinru  阅读(239)  评论(0编辑  收藏  举报