POJ 2762 Going from u to v …(强连通分量+拓扑排序)

POJ 2762 Going from u to v …(强连通分量+拓扑排序)

http://poj.org/problem?id=2762

题意:

      给你一个有向图,如果对于图中的任意一对点u和v(即所有两点都需要满足)都有一条从u到v的路或从v到u的路,那么就输出’Yes’,否则输出’No’.

分析:

       首先求出该图的所有强连通分量,对于分量中的任意两点肯定都是有路的。我们只需要判断不同分量内的点是否有路即可。

       把所有分量缩点,构成一个新的DAG图。现在的问题变成了:该DAG图是否对于任意两点都存在一条路。(想想为什么这个问题与原问题等价)

      什么时候DAG图满足上述条件呢?多画几个图可以知道该DAG图只能是一条链的时候才行(自己画图验证一下,注意DAG图无环),即该DAG图拓扑排序时产生的是全序排列。(队列中始终只有一个元素)

AC代码:

#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1000+10;
int n,m;
vector<int> G[maxn],G2[maxn];
stack<int> S;
int dfs_clock, scc_cnt;
int pre[maxn],low[maxn],sccno[maxn];
int in[maxn];//新图的入度
void dfs(int u)
{
    pre[u]=low[u]=++dfs_clock;
    S.push(u);
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!pre[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v])
            low[u]=min(low[u],pre[v]);
    }
    if(low[u]==pre[u])
    {
        scc_cnt++;
        while(true)
        {
            int x=S.top(); S.pop();
            sccno[x]=scc_cnt;
            if(x==u) break;
        }
    }
}
void find_scc(int n)
{
    scc_cnt=dfs_clock=0;
    memset(pre,0,sizeof(pre));
    memset(sccno,0,sizeof(sccno));
    for(int i=1;i<=n;i++)
        if(!pre[i]) dfs(i);
}
bool topo()
{
    stack<int> Q;
    int sum=0;//记录出Q的节点总数
    for(int i=1;i<=scc_cnt;i++)
        if(in[i]==0) Q.push(i);
    while(!Q.empty())
    {
        if(Q.size()>1) return false;
        int u=Q.top(); Q.pop();
        sum++;
        for(int i=0;i<G2[u].size();i++)
        {
            int v=G2[u][i];
            if(--in[v]==0) Q.push(v);
        }
    }
    return sum==scc_cnt;
}
int main()
{
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) G[i].clear();
        while(m--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
        }
        find_scc(n);
        //下面是对新图拓扑排序
        bool map[maxn][maxn];
        memset(map,0,sizeof(map));
        for(int i=1;i<=scc_cnt;i++) G2[i].clear();
        memset(in,0,sizeof(in));
        for(int u=1;u<=n;u++)
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            int x=sccno[u],y=sccno[v];
            if(!map[x][y] && x!=y)
            {
                G2[x].push_back(y);
                map[x][y]=true;
                in[y]++;
            }
        }
        printf("%s\n",topo()?"Yes":"No");
    }
    return 0;
}


你可能感兴趣的:(Algorithm,算法,ACM)