poj 2762 Going from u to v or fr…

题意:有N个山洞m条路,问任意两点x y 能否存在从x到y 或者从y到x。

思路:注意是或 而不是和。所以缩点后,不是判断强连通为1。
第一种方法:只要用拓扑判断入度为0的点是否为1个,如果有多个,就出现在分叉,不可能从x到y。
第二种方法:从入度为0的点 DFS 搜索 最长能到达的路径 如果路径长度等于点数,说明可以从源点访问完所有点。

第二种做法的代码:

#include <stdio.h>
#include <string.h>
#define VM 1005
#define EM 6005

struct E
{
      int to,next;
}edge[EM],edge1[EM];
int head[VM],head1[VM],indeg[VM],outdeg[VM];
int dfn[VM],low[VM],vis[VM],belong[VM],stack[VM];
int scc,cnt,top,p,n;

void addedge (int cu,int cv,E ed[],int head0[])
{
      ed[p].to = cv;
      ed[p].next = head0[cu];
      head0[cu] = p++;
}

void tarjan (int u)
{
      int v;
      dfn[u] = low[u] = ++cnt;
      stack[top++] = u;
      vis[u] = 1;
      for (int i = head[u];i != -1;i = edge[i].next)
      {
              v = edge[i].to;
              if (!dfn[v])
              {
                      tarjan(v);
                      low[u] = low[u] > low[v]?low[v]:low[u];
              }
              else if (vis[v]&&low[u] > dfn[v])
                      low[u] = dfn[v];
      }
      if (dfn[u] == low[u])
      {
              ++scc;
              do
              {
                      v = stack[--top];
                      vis[v] = 0;
                      belong[v] = scc;
              } while (u != v);
      }
}
void sovle ()
{
      int u;
      scc = top = cnt = 0;
      memset (dfn,0,sizeof(dfn));
      memset (vis,0,sizeof(vis));
      for (u = 1;u <= n;u ++)
              if (!dfn[u])
                      tarjan(u);
}

int dep[VM], maxdep;

int DFS(int u, int d) //找最长路径
{
      int i, v;
      dep[u] = d;
      maxdep = maxdep > d ? maxdep : d;
      for (i = head1[u]; i != -1; i = edge1[i].next)
      {
            v = edge1[i].to;
            if (dep[u] > dep[v])
                  DFS(v, d + 1);
      }
      return 0;
}

int ans()
{
      int u,v,i;
      memset (indeg,0,sizeof(indeg));
    // memset (outdeg,0,sizeof(outdeg));
      //memset (count,0,sizeof(count));
      for (u = 1;u <= n;u ++)
              for (i = head[u];i != -1;i = edge[i].next)
              {
                      v = edge[i].to;
                      if (belong[u] != belong[v])
                      {
                              indeg[belong[v]] ++;
                          //  outdeg[belong[u]] ++;
                              addedge (belong[u],belong[v],edge1,head1);      //建新图
                      }
              }
      maxdep = 0;
      for (u = 1;u <= n;u ++)
              if (!indeg[u])
              {
                      DFS(u,1);
                      break;
              }
      if (maxdep == scc)
              return 1;
      return 0;
}

int main ()
{
      int t,m,u,v;
      scanf ("%d",&t);
      while (t --)
      {
              p = 0;
            memset (head1,-1,sizeof(head1));
              memset (head,-1,sizeof(head));
              scanf ("%d%d",&n,&m);
              while (m --)
              {
                      scanf ("%d%d",&u,&v);
                      addedge (u,v,edge,head);
              }
              sovle ();
              if (ans())
                      printf ("Yes\n");
              else
                      printf("No\n");
      }
      return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值