poj 2762(弱联通:强连通+缩点+拓扑排序)

题意:给出n个点和m条边,接着给出直接相连的边(注意是有向边),求解任意x,y两点间是否存在x可到达y或者y可 
到达x,如果任意x和y都满足这样的条件就输出"Yes",否则输出"No". 
 先求解出该有向图的强连通分量,然后根据求解出来的强连通分量进行缩点重新建图, 
 那么问题就转换为求解在新图中是否存在一条能走完所有的顶点的路径,这时可以对缩点后的新图进行拓扑排序, 
 看拓扑排序是否可以成功进行(可以通过在拓扑排序的过程中入度为0的顶点个数来进行判断), 
 如果存在拓扑排序并且是唯一的话说明缩点后的新图存在一条能走完所有顶点的路径. 
  考点:强连通、拓扑排序过程,返回是否成功,stack存拓扑排序的结果 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
using namespace std;
const int N=1005;
int n,m;
vector<int>Grap[N];
stack<int>mystack;
int map[N][N];
int cnt=0;
int tmp=0;
int vis[N];
int dfn[N];
int low[N];
int fa[N];
int in[N];
stack<int>S;
vector<int>new_G[N];


void init()
{
    for(int i=1;i<=n;i++)
      Grap[i].clear();
    for(int j=1;j<=n;j++)
      new_G[j].clear();
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(in,0,sizeof(in));
    memset(low,0,sizeof(low));
    memset(fa,0,sizeof(fa));
    tmp=0;
    cnt=0;
    while(!S.empty())
    S.pop();
    while(!mystack.empty())
    mystack.pop();
}


void tarjan(int u)
{
    vis[u]=1;
    dfn[u]=low[u]=tmp++;
    mystack.push(u);
    for(int i=0;i<Grap[u].size();i++)
    {
        int v=Grap[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[v],low[u]);
        }
        else if(vis[v])
        low[u]=min(dfn[v],low[u]);
    }
    if(dfn[u]==low[u])
    {
      cnt++;
      int t;
      do
      {
        t=mystack.top();
        mystack.pop();
        vis[t]=0;
        fa[t]=cnt;
      }while(t!=u);
    }
}


int tuopu()
{
    while(!S.empty())
      S.pop();
    int sum=0;
    for(int i=1;i<=cnt;i++)
    {
        if(in[i]==0)
        {
            sum++;
            if(sum>=2)
            return -1;
            S.push(i);
        }
    }


    while(cnt--)
    {
      int top=S.top();
      S.pop();
      int sum=0;
      for(int i=0;i<new_G[top].size();i++)
      {
          int v=new_G[top][i];
           in[v]--;
          if(in[v]==0)
          {
            sum++;
            S.push(v);
          }
      }
      if(sum>=2)
        return -1;
    }
    return 1;
}


int main()
{
    int cas;
    int u,v;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d%d",&n,&m);
        if(n==0||n==1)
        {
            cout<<"No"<<endl;
            continue;
        }
        init();
        for(int i=0;i<m;i++)
        {
          scanf("%d%d",&u,&v);
          Grap[u].push_back(v);
        }


        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
            {
              tarjan(i);
            }
        }
        memset(map,0,sizeof(map));
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<Grap[i].size();j++)
            {
              int v=Grap[i][j];
              if(!map[fa[i]][fa[v]]&&fa[i]!=fa[v])
              {
                 new_G[fa[i]].push_back(fa[v]);
                 map[fa[i]][fa[v]]=1;
                 in[fa[v]]++;
              }
            }
        }
        int ans=tuopu();
        if(ans==-1)
        cout<<"No"<<endl;
        else
        cout<<"Yes"<<endl;
    }
  return 0;
}


你可能感兴趣的:(poj 2762(弱联通:强连通+缩点+拓扑排序))