POJ 2762 Going from u to v or from v to u?

 

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

思路:

1、注意是或而不是和,所以“缩点”后,由于“缩点”内的点相互可达,所以不需要管“缩点”内的点。注意,不是判断强连通的数量为1,而是判断是否是弱连通。

2、如果两点不可达那么在拓扑排序时,该两点谁也不是谁的前驱和后继,所以在拓扑排序时只要同时出现至少两个入度为0的点,那么这些点一定互不可达,所以只要判断拓扑的方式是否唯一即可。

第一种方法:只要用拓扑判断入度为0的点是否为1个,如果有多个,就出现在分叉,不可能从x到y。

第二种方法:从入度为0的点DFS搜索最长能到达的路径如果路径长度等于点数,说明可以从源点访问完所有点。

 

知识充电: 

强连通图:在有向图中, 若对于每一对顶点v1和v2, 都存在一条从v1到v2和从v2到v1的路径,则称此图是强连通图.

弱连通图:将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。

单向连通图:如果有向图中,对于任意节点v1和v2,至少存在从v1到v2和从v2到v1的路径中的一条,则原图为单向连通图。

 

三者之间的关系是,强连通图必然是单向连通的,单向连通图必然是弱连通图。

CODE:

 

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

#define MAXN 50010
#define MAXM 100010

struct Edge
{
    int v, next;
}edge[MAXM], edge2[MAXM];

int first[MAXN], first2[MAXN],stack[MAXN], ins[MAXN], dfn[MAXN], low[MAXN];
int belong[MAXM];
int ind[MAXN], outd[MAXN], topo[MAXN];

int n, m;
int cnt, cnt2;
int scnt, top, tot;

void init()
{
    cnt = 0, cnt2 = 0;
    scnt = top = tot = 0;
    memset(dfn, 0sizeof(dfn));
    memset(first, -1sizeof(first));
    memset(first2, -1sizeof(first2));
    memset(ins, 0sizeof(ins));
    memset(ind, 0sizeof(ind));
    //memset(outd, 0, sizeof(outd));
    
//memset(topo, 0, sizeof(topo));
}

void read_graph(int u, int v)
{
    edge[cnt].v = v;
    edge[cnt].next = first[u];
    first[u] = cnt++;
}

void read_graph2(int u, int v) //重构图 
{
    edge2[cnt2].v = v;
    edge2[cnt2].next = first2[u], first2[u] = cnt2++;
}

void dfs(int u)
{
    int v;
    dfn[u] = low[u] = ++tot;
    ins[u] = 1;
    stack[top++] = u;
    for(int e = first[u]; e != -1; e = edge[e].next)
    {
        v = edge[e].v;
        if(!dfn[v])
        {
            dfs(v);
            low[u] = min(low[u], low[v]);
        }
        else if(ins[v])
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(dfn[u] == low[u])
    {
        scnt++;
        do
        {
            v = stack[--top];
            belong[v] = scnt;
            ins[v] = 0;
        }while(v != u);
    }
}

void Tarjan()
{
    for(int v = 1; v <= n; v++) if(!dfn[v])
        dfs(v);
//Tarjan 

int toposort()
{
    queue<int> q;
    int tot2 = 0;
    for(int i = 1; i <= scnt; i++) if(!ind[i]) q.push(i);
    if(q.size() > 1return 0;
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        topo[++tot2] = x;
        for(int e = first2[x]; e != -1; e = edge2[e].next)
        {
            int v = edge2[e].v;
            if(--ind[v] == 0)
            {
                q.push(v);
            }
        }
        if(q.size() > 1return 0;
    }
    if(tot2 != scnt) return 0;
    else return 1;
//toposort 

void solve()
{
    Tarjan();
    for(int u = 1; u <= n; u++) //重构图 
    {
        for(int e = first[u]; e != -1; e = edge[e].next)
        {
            int v = edge[e].v;
            if(belong[u] != belong[v])
            {
                ind[belong[v]]++;
                read_graph2(belong[u], belong[v]);
            }
        }
    }
    if(toposort()) printf("Yes\n");
    else printf("No\n");
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        init();
        scanf("%d%d", &n, &m);
        while(m--)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            read_graph(u, v);
        }
        solve();
    }
    return 0;
}

 

posted on 2012-10-31 11:33  有间博客  阅读(432)  评论(0)    收藏  举报