poj 1904 强连通

传送门

题意:国王有n个儿子,另有n个妹子,儿子要把妹子,每个儿子都自己喜欢的妹子们,问每个儿子可以怎样选择,然后不影响其他儿子把妹。

思路:先从儿子到喜欢的妹子建立有向边,然后根据男巫给的配对方案从妹子到儿子建立有向边,然后计算强连通分量,然后对于每个儿子可以选择的就是和自己在一个强连通分量里的喜欢的妹子。

看wwj的博客,见他吐槽国王儿子太多,我也吐槽下。2000个儿子!!!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;
stack<int>st;
int n,m,bnum,scnum,fst[4005],next[300005],node[300005];
int num,low[4005],dfn[4005],d[4005],ans[4005],anum;
bool inst[4005];
//inline void RD(int &ret)
//{
//    char c;
//    do
//    {
//        c=getchar();
//    }
//    while(c<'0'||c>'9');
//    ret=c-'0';
//    while((c=getchar())>='0'&&c<='9')ret=ret*10+(c-'0');
//}
//
//inline void OT(int a)
//{
//    if(a>= 10)OT(a/10);
//    putchar(a%10+'0');
//}
int in()
{
    char ch;
    int a=0;
    while((ch=getchar())==' '||ch=='\n');
    a += ch - '0';
    while((ch=getchar())!=' '&&ch!='\n')
    {
        a*=10;
        a+=ch-'0';
    }
    return a;
}
void out(int a)
{
    if(a>=10)out(a/10);
    putchar(a%10+'0');
}
void init()
{
    int u,v;
    num=bnum=scnum=0;
    memset(fst,-1,sizeof(fst));
    memset(dfn,0,sizeof(dfn));
    memset(inst,0,sizeof(inst));
    for(int i=1; i<=n; i++)
    {
        //scanf("%d",&m);
        //RD(m);
        m=in();
        for(int j=0; j<m; j++)
        {
            //scanf("%d",&v);
            //RD(v);
            v=in();
            v+=n;
            next[++bnum]=fst[i];
            fst[i]=bnum;
            node[bnum]=v;
        }
    }
    for(int i=1; i<=n; i++)
    {
        //scanf("%d",&v);
        //RD(v);
        v=in();
        v+=n;
        next[++bnum]=fst[v];
        fst[v]=bnum;
        node[bnum]=i;
    }
}
void tarjan(int u)
{
    int v;
    dfn[u]=low[u]=++num;
    st.push(u);
    inst[u]=1;
    for(int i=fst[u]; i!=-1; i=next[i])
    {
        v=node[i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(inst[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        scnum++;
        do
        {
            v=st.top();
            st.pop();
            inst[v]=0;
            d[v]=scnum;
        }
        while(u!=v);
    }
}
void solve()
{
    for(int i=1; i<=n; i++)
    {
        if(!dfn[i])tarjan(i);
    }
    for(int i=1; i<=n; i++)
    {
        anum=0;
        for(int j=fst[i]; j!=-1; j=next[j])
        {
            int v=node[j];
            if(d[i]==d[v])
            {
                ans[anum++]=v-n;
            }
        }
        sort(ans,ans+anum);
        //printf("%d",anum);
        out(anum);
        for(int j=0; j<anum; j++)//printf(" %d",ans[j]);
        {
            //printf(" ");
            putchar(' ');
            out(ans[j]);
        }
        //printf("\n");
        putchar('\n');
    }
}
int main()
{
    //scanf("%d",&n);
    //RD(n);
    n=in();
    init();
    solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值