POJ - 1904 King's Quest (强连通)

题意:有N个王子,每个王子有任意个喜欢的妹子,巫师会给出一个方案:每个妹子都嫁给一个王子。但是国王希望知道:每个王子能在哪些妹子中择偶而不影响其他王子择偶。

分析:设王子为x部,妹子为y部,假设有匹配xi与yi和xj和yj,当xi中意yj且xj中意yi时。那么xi,xj改变对象不会影响最大匹配数。可以将寻找新的伴侣与匈牙利算法中寻找增广路的过程联想在一起。如果在这几对人中能找到一条完整地交错轨,那么就可以对Y部进行任意选择。

所以本题转化为球每个强连通分量中的点。

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn =4e3+5,maxm = 3e5+5;
const int INF =0x3f3f3f3f;
struct Edge{int to,next;}edges[maxm];
int head[maxn],tot;
stack<int> S;
int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt;
int sccnum[maxn];
void init(int N)
{
    tot=dfn=scc_cnt=0;
    memset(pre,0,sizeof(pre));
    memset(sccno,0,sizeof(sccno));
    memset(head,-1,sizeof(head));
}

void AddEdge(int u,int v)   {
    edges[tot] = (Edge){v,head[u]};
    head[u] = tot++;
}
void Tarjan(int u)
{
    int v;
    pre[u]=low[u]=++dfn;
    S.push(u);
    for(int i=head[u];~i;i=edges[i].next){
        v= edges[i].to;
        if(!pre[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v]){
            low[u]=min(low[u],pre[v]);
        }
    }
    if(pre[u]==low[u]){
        int x;
        ++scc_cnt;
        for(;;){
            x = S.top();S.pop();
            sccno[x]=scc_cnt;
            if(x==u)break;
        }
    }    
}
int Scan()     //输入外挂
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
void Out(int a)    //输出外挂
{
    if(a>9)
        Out(a/10);
    putchar(a%10+'0');
}

int res[maxn];
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int N,u,v,k,tmp;
    while(scanf("%d",&N)==1){
        init(N*2);
        for(int i=1;i<=N;++i){
            k = Scan();
            while(k--){
                v = Scan();
                AddEdge(i,v+N);
            }
        }
        for(int i=1;i<=N;++i){
            u = Scan();
            AddEdge(u+N,i);
        }
        for(int i=1;i<=2*N;++i){
            if(!pre[i])
                Tarjan(i);
        }
        for(int u=1;u<=N;++u){
            int cnt=0;
            for(int i=head[u];~i;i=edges[i].next){
                int v = edges[i].to;
                if(sccno[u]==sccno[v]){
                    res[cnt++] = v-N;
                }
            }
            sort(res,res+cnt);
            Out(cnt);
            for(int i=0;i<cnt;++i){
                putchar(' ');
                Out(res[i]);
            }
            putchar('\n');
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xiuwenli/p/9486705.html