poj 2762

/*
强连通+缩点+搜索特殊处理,求单向连通
这一题的符合条件的图经过缩点重构后为拓扑图。
对于重新构造出的新图,判断这个图是否单向连通

若结点的后继大于等于2个,则需判断这些所有的后继是之间
否为单向连通,然后搜索所有点。
从中找到的规律为:
入度为0的点有且仅有一个,删除这个点后的图中,入度为0的点依然有且仅有一个
因此只需判断入度为0的结点个数即可判断是否单向连通
*/
#include <stdio.h>
#include <string.h>
#include <vector>
#include <stack>

using namespace std;

vector<int>G1[1005];
vector<int>G2[1005];
stack<int>S;

int index,bcnt,flag;
int dfn[1005],low[1005],belong[1005],instack[1005],indegree[1005];

void tarjan(int i)
{
    int u,j;
    S.push(i);
    dfn[i] = low[i] = ++index;
    instack[i] = 1;
    for(j=0; j<G1[i].size(); j++)
    {
        u = G1[i][j];
        if (!dfn[u])
        {
            tarjan(u);
            low[i] = min(low[u],low[i]);
        }
        else if (instack[u])
            low[i] = min(dfn[u],low[i]);
    }
    if (dfn[i] == low[i])
    {
        bcnt++;
        do
        {
            u = S.top();
            belong[u] = bcnt;
            S.pop();
            instack[u] = 0;
        }
        while (u != i);
    }
}

void search(int i)
{
    int j,t,sum = 0;
    for(j=0; j<G2[i].size(); j++)
    {
        indegree[G2[i][j]]--;//去除根结点i后,i的所有后继入度减1
        if (indegree[G2[i][j]] == 0)//找出根结点
        {
            t = G2[i][j];
            sum++;
        }
    }
    if (sum > 1)
    {
        flag = 0;
        return ;
    }
    else if (sum == 1)
    {
        search(t);
    }
}

int main(void)
{
    int T,n,m,a,b,i,j,k,t,sum;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        for(i=1; i<=n; i++)
        {
            G1[i].clear();
            G2[i].clear();
        }
        while (m--)
        {
            scanf("%d%d",&a,&b);
            G1[a].push_back(b);
        }
        index = bcnt = 0;
        memset(dfn,0,sizeof(dfn));
        for(i=1; i<=n; i++)
            if (!dfn[i])
                tarjan(i);
        memset(indegree,0,sizeof(indegree));
        for(i=1; i<=bcnt; i++)
            for(j=1; j<=n; j++)
                if (belong[j] == i)
                    for(k=0; k<G1[j].size(); k++)
                        if (i != belong[G1[j][k]])
                        {
                            G2[i].push_back(belong[G1[j][k]]);
                            indegree[belong[G1[j][k]]]++;//记录结点入度
                        }
        flag = 1;
        sum = 0;
        for(i=1; i<=bcnt; i++)
        {
            if (indegree[i] == 0)//入度为0的为根结点,从这个点开始搜索
            {
                t = i;
                sum++;
            }
        }
        if (sum > 1)//多于1个则不符合
            flag = 0;
        else
            search(t);
        if (flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

 

posted @ 2014-03-20 23:41  辛力啤  阅读(142)  评论(0编辑  收藏  举报