POJ-2762 Going from u to v or from v to u? (强连通分量[Tarjan]&&(拓扑排序||树形DP))

此处有 目录↑
Going from u to v or from v to u?
http://poj.org/problem?id=2762
Time Limit: 2000MS   Memory Limit: 65536K
     

Description

In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors connecting some rooms. Each time, Wind choose two rooms x and y, and ask one of their little sons go from one to the other. The son can either go from x to y, or from y to x. Wind promised that her tasks are all possible, but she actually doesn't know how to decide if a task is possible. To make her life easier, Jiajia decided to choose a cave in which every pair of rooms is a possible task. Given a cave, can you tell Jiajia whether Wind can randomly choose two rooms without worrying about anything?

Input

The first line contains a single integer T, the number of test cases. And followed T cases. 

The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly. 

Output

The output should contain T lines. Write 'Yes' if the cave has the property stated above, or 'No' otherwise.

Sample Input

1
3 3
1 2
2 3
3 1

Sample Output

Yes

题目大意:给定一个有向图,判断是否对任意两点u,v,有u可达v 或 v可达u?


先找出所有的强连通分量,则各强连通分量内是相互可达的,只用判断强连通分量之间是否至少单向可达

将各强连通分量缩成一点,建立新图,则新图是DAG

刚开始也认为只要从一个入度为0的点到出度为0的点的长度为总点数,就满足题意,否则不行,但是看见有人说不是只有一条链的情况下会输出Yes,于是放弃了

最终用拓扑排序AC,若某次队列中点的数目大于1(则这些点之间不能单向可达),则输出No,否则输出Yes

没有初始化indeg数组,导致WA了很久都没看出来...


解法一:Tarjan&&拓扑排序

#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int MAXN=1005;

int n,m,num,cnt,ans,top,head,tail;
int stak[MAXN],que[MAXN];
int low[MAXN],dfn[MAXN],color[MAXN],indeg[MAXN];//biocks[i]表示删掉i点后,能形成的连通块数
vector<int> g[MAXN];
bool isIn[MAXN],mp[MAXN][MAXN];

void Tarjan(int u,int p) {
    stak[++top]=u;
    isIn[u]=true;
    dfn[u]=low[u]=++num;
    int v;
    for(int i=0;i<g[u].size();++i) {
        v=g[u][i];
        if(dfn[v]==0) {
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(isIn[v]&&dfn[v]<low[u])
            low[u]=dfn[v];
    }

    if(dfn[u]==low[u]) {
        ++cnt;
        do {
            v=stak[top--];
            isIn[v]=false;
            color[v]=cnt;//同一个强连通分量缩成一个点
        } while(v!=u);
    }
}

bool TopoSort() {
    head=tail=0;
    for(int i=1;i<=cnt;++i)
        if(indeg[i]==0)
            que[tail++]=i;
    if(tail-head>1)//如果入度为0的点超过一个,则这些点不能相互单向可达
        return false;
    int u;
    while(head!=tail) {
        u=que[head++];
        for(int i=1;i<=cnt;++i) {
            if(mp[u][i]) {
                --indeg[i];
                if(indeg[i]==0)//入度为0的点入队
                    que[tail++]=i;
            }
        }
        if(tail-head>1)//如果入度为0的点超过一个,则这些点不能相互单向可达
            return false;
    }
    return true;
}

int main() {
    int T,s,e;
    scanf("%d",&T);
    while(T-->0) {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) {
            g[i].clear();
            dfn[i]=indeg[i]=0;
            isIn[i]=false;
        }
        while(m-->0) {
            scanf("%d%d",&s,&e);
            g[s].push_back(e);
        }

        cnt=num=top=0;//cnt表示强连通分量
        for(int i=1;i<=n;++i) {
            if(dfn[i]==0)
                Tarjan(i,0);
        }
        memset(mp,false,sizeof(mp));
        for(int i=1;i<=n;++i) {
            for(int j=0;j<g[i].size();++j) {
                s=color[i];
                e=color[g[i][j]];
                if(s!=e&&!mp[s][e]) {//建立新图,不考虑重边
                    mp[s][e]=true;
                    ++indeg[e];
                }
            }
        }
        printf("%s\n",TopoSort()?"Yes":"No");
    }
    return 0;
}


解法二:Tarjan&&树形DP

又想了想,即使新图不是一条链,但是满足题意的情况下,必定有一条路径满足:入度为0的点到出度为0的点的所经过的点的个数等于所有点的个数

dp[i]表示从i点出发,一条路径上能经过的点数的最大值

#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int MAXN=1005;

int n,m,num,cnt,ans,top;
int stak[MAXN];
int low[MAXN],dfn[MAXN],color[MAXN],dp[MAXN];//biocks[i]表示删掉i点后,能形成的连通块数
vector<int> g[MAXN],mp[MAXN];
bool isIn[MAXN],haveIndeg[MAXN];

void Tarjan(int u,int p) {
    stak[++top]=u;
    isIn[u]=true;
    dfn[u]=low[u]=++num;
    int v;
    for(int i=0;i<g[u].size();++i) {
        v=g[u][i];
        if(dfn[v]==0) {
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(isIn[v]&&dfn[v]<low[u])
            low[u]=dfn[v];
    }

    if(dfn[u]==low[u]) {
        ++cnt;
        do {
            v=stak[top--];
            isIn[v]=false;
            color[v]=cnt;//同一个强连通分量缩成一个点
        } while(v!=u);
    }
}

void dfs(int u) {
    if(dp[u]!=-1)
        return ;
    if(mp[u].size()==0) {//如果点u是叶子节点,则其能经过的点数为1
        dp[u]=1;
        return ;
    }
    for(int i=0;i<mp[u].size();++i) {
        dfs(mp[u][i]);
        dp[u]=max(dp[u],dp[mp[u][i]]+1);//点u的经过的点的个数为其各子结点经过的点的个数+1
    }
}

bool Judge() {
    cnt=num=top=0;//cnt表示强连通分量
    for(int i=1;i<=n;++i) {
        if(dfn[i]==0)
            Tarjan(i,0);
    }
    int s,e,sta;
    memset(mp,false,sizeof(mp));
    for(int i=1;i<=n;++i) {
        for(int j=0;j<g[i].size();++j) {
            s=color[i];
            e=color[g[i][j]];
            if(s!=e) {//建立新图
                mp[s].push_back(e);
                haveIndeg[e]=true;;
            }
        }
    }

    num=0;
    for(int i=1;i<=cnt;++i) {
        dp[i]=-1;
        if(!haveIndeg[i]) {
            sta=i;
            ++num;
        }
    }
    if(num>1)
        return false;
    dfs(sta);
    return dp[sta]==cnt;//判断入度为0的点能达到的最大深度是否等于点的个数
}

int main() {
    int T,s,e;
    scanf("%d",&T);
    while(T-->0) {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) {
            g[i].clear();
            mp[i].clear();
            dfn[i]=0;
            isIn[i]=haveIndeg[i]=false;
        }
        while(m-->0) {
            scanf("%d%d",&s,&e);
            g[s].push_back(e);
        }

        printf("%s\n",Judge()?"Yes":"No");
    }
    return 0;
}


你可能感兴趣的:(poj,拓扑排序,Tarjan,树形DP,连通分量)