hoj 3005 Game Rigging 强联通分量求缩点

/*

 

题目:

    现给出各位选手的能力比较并给出自己的朋友的参赛号码,如何组织比赛使得自己的朋友能够获胜

 

分析:

    各选手能力比较可以构造一个有向图,而想要使得自己的朋友要赢得比赛,所以他的所在的连通块

    必定是入度为0的(假设建图时是以能力大的人作为边的起点)。所以题目可以转换为先建图,然后

    再找连通块求缩点,然后判断该缩点是否入度为0,若有朋友在该连通块中,即可判断可以组织这样

    的一场比赛。而判断朋友在不在该连通块中,可以先求到所有的入度为0的连通块用数组置为true,

    然后直接把所有朋友的所在的连通块置为false,若所有的连通块中只要还有true的连通块,就可判断

    不能组织这样的一场比赛

 

*/

#include <cstdio>

#include <cstring>

 

const int X = 100005;

 

int dfn[X],low[X],stack[X],deg[X],father[X],depth,top,bcnt;

int f[X],fri,n,m;

bool use[X],instack[X];

 

struct node

{

    int v;

    node *next;

    void fun()

    {

        v = 0;

        next = NULL;

    }

}edge[X],*head[X],*tmp;

 

void tarjan(int u)

{

    int v;

    dfn[u] = low[u] = ++depth;

    stack[++top] = u;

    instack[u] = true;

 

    for(node *p=head[u];p;p=p->next)

    {

        v = p->v;

        if(!low[v])

        {

            tarjan(v);

            if(low[v]<low[u])

                low[u] = low[v];

        }

        else if(instack[v]&&low[u]>dfn[v])

            low[u] = dfn[v];

    }

    if(low[u]==dfn[u])

    {

        bcnt++;

        do

        {

            v = stack[top--];

            instack[v] = false;

            father[v] = bcnt;

        }while(u!=v);

    }

}

 

void solve()

{

    memset(instack,false,sizeof(instack));

    memset(low,0,sizeof(low));

    memset(deg,0,sizeof(deg));

    depth = bcnt = top = 0;

 

    for(int i=1;i<=n;i++)

        if(!low[i])

            tarjan(i);

 

    for(int i=1;i<=n;i++)

        for(node *p=head[i];p;p=p->next)

            if(father[i]!=father[p->v])

                deg[father[p->v]]++;

 

    memset(use,false,sizeof(use));

    for(int i=1;i<=bcnt;i++)

        if(!deg[i])

            use[i] = true;

 

    for(int i=0;i<fri;i++)

        use[father[f[i]]] = false;

 

    bool flag = true;

    for(int i=1;i<=bcnt;i++)

        if(use[i])

        {

            flag = false;

            break;

        }

    flag?printf("yes\n"):printf("no\n");

}

 

int main()

{

    freopen("sum.in","r",stdin);

    freopen("sum.out","w",stdout);

    while(scanf("%d%d%d",&n,&fri,&m),n||m||fri)

    {

        for(int i=0;i<fri;i++)

            scanf("%d",&f[i]);

        memset(head,NULL,sizeof(head));

 

        for(int i=0;i<m;i++)

            edge[i].fun();

        tmp = edge;

        int u,v;

        for(int i=0;i<m;i++)

        {

            scanf("%d%d",&u,&v);

            tmp->next = head[u];

            tmp->v = v;

            head[u] = tmp++;

        }

        solve();

    }

 

    return 0;

}

posted @ 2012-05-18 16:18  yejinru  阅读(235)  评论(0编辑  收藏  举报