poj 1904 强连通分量

思路:先有每个儿子向所有他喜欢的姑娘建边,对于最后给出的正确匹配,我们建由姑娘到相应王子的边。和某个王子在同一强连通分量,且王子喜欢的姑娘都是该王子能娶得。思想类似匈牙利算法求匹配的时候,总能找到增广路径。

代码比较烂,跑了近6s。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

#include<vector>

#define Max(a,b) ((a)>(b)?(a):(b))

#define Min(a,b) ((a)<(b)?(a):(b))

#define Maxn 4010

#define Maxm 400010

using namespace std;

int dfn[Maxn],low[Maxn],vi[Maxn],Stack[Maxn],head[Maxn],id[Maxn],n,e,lab,num,top,ans[Maxn],match[2010][2010];

struct Edge{

    int u,v,next;

}edge[Maxm];

vector<int> q[Maxn];

void init()

{

    memset(dfn,0,sizeof(dfn));

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

    memset(vi,0,sizeof(vi));

    memset(head,-1,sizeof(head));

    memset(id,0,sizeof(id));

    memset(match,0,sizeof(match));

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

        q[i].clear();

    e=lab=num=top=0;

}

void add(int u,int v)

{

    edge[e].u=u,edge[e].v=v,edge[e].next=head[u],head[u]=e++;

}

int Tarjan(int u)

{

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

    vi[u]=1;

    Stack[top++]=u;

    int i,j,v;

    for(i=head[u];i!=-1;i=edge[i].next)

    {

        v=edge[i].v;

        if(!dfn[v])

        {

            Tarjan(v);

            low[u]=min(low[u],low[v]);

        }

        if(vi[v])

            low[u]=min(low[u],dfn[v]);

    }

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

    {

        ++num;

        do{

            i=Stack[--top];

            vi[i]=0;

            id[i]=num;

        }while(i!=u);

    }

    return 0;

}

void solve()

{

    int i,j;

    for(i=1;i<=2*n;i++)

        if(!dfn[i])

        Tarjan(i);

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

    {

        q[id[i]].push_back(i-n);

    }

    int cnt=0;

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

    {

        int size=q[id[i]].size();

        cnt=0;

        for(j=0;j<size;j++)

        {

            if(match[i][q[id[i]][j]])

                ans[cnt++]=q[id[i]][j];

        }

        printf("%d",cnt);

        for(j=0;j<cnt;j++)

            printf(" %d",ans[j]);

        printf("\n");

    }

}

int main()

{

    int a,b,i,j;

    while(scanf("%d",&n)!=EOF)

    {

        init();

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

        {

        scanf("%d",&a);

        while(a--)

        {

            scanf("%d",&b);

            add(i,b+n);

            match[i][b]=1;

        }

        }

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

        {

            scanf("%d",&a);

            add(a+n,i);

        }

        solve();

    }

    return 0;

}

 

你可能感兴趣的:(poj)