HDU 4685 Prince and Princess

来源:互联网 发布:喊麦特效软件 编辑:程序博客网 时间:2024/04/30 15:53

2013 暑假多校训练 8 总结

题目

题意:

有n个王子,m个公主,王子可以喜欢很多个公主,每个王子可以娶一个公主,每个公主可以嫁一个王子,这样可以得到一个最大匹配,对每个王子,求出他选择娶那些公主不影响到最大匹配。

解法:

一开始,想到的做法是所有的王子向其喜欢的公主连边,做一遍二分图后,每个公主向选择了她的王子连边,这样,如果某个王子喜欢的两个公主在同一个强联通分量里的话,说明这个强联通分量里面的边都能取反向,则同一强联通分量里的公主和王子存在另一种方式配对,但是,这种方法处理不了某些王子娶不到公主,或者公主嫁不出去的情况。

考虑如何将上述情况转成所有公主和王子都能终成眷属的情况。对于每一个娶不到老婆的王子都弄一个虚拟的公主,这个公主被所有的王子喜欢(让这个王子和他可以娶到的真的公主在同一个强联通分量),对于每一个嫁不出了的公主都弄一个虚拟的王子,这个王子喜欢所有的公主,同理。

实现代码的时候,可以省去王子向公主连边,改成王子要娶的公主向他喜欢的其他的公主连边。

代码写的很丑,写了两个二分图匹配,跑得很慢==,懒得删掉第二次匹配了

代码:

#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>using namespace std;#define maxn 1005int n,m,N,n2,m2;bool g[maxn][maxn],state[maxn],insta[maxn];int cnt,top,ind,to[maxn],result[maxn],dfn[maxn],low[maxn],sta[maxn],bel[maxn],tmp[maxn];struct node{    int v,next;}e[maxn*maxn];int ecnt,pre[maxn];void add(int u,int v){    e[ecnt].v=v;    e[ecnt].next=pre[u];    pre[u]=ecnt++;}int find(int x){    for (int i=1;i<=m;i++)        if (!state[i]&&g[x][i])        {            state[i]=1;            if (!result[i]||find(result[i]))            {                result[i]=x;                return 1;            }        }    return 0;}int hungry(){    int res=0;    memset(result,0,sizeof(result));    for (int i=1;i<=n;i++)    {        memset(state,0,sizeof(state));        if (find(i)) res++;    }    return res;}void tarjan(int u){    dfn[u]=low[u]=++ind;    sta[++top]=u;    insta[u]=1;    for (int i=pre[u];i!=-1;i=e[i].next)    {        int v=e[i].v;        if (!dfn[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);        }        else if (insta[v])            low[u]=min(low[u],dfn[v]);    }    if (low[u]==dfn[u])    {        ++cnt;        int v;        do        {            v=sta[top--];            insta[v]=0;            bel[v]=cnt;        }while (u!=v);    }}void solve(){    top=cnt=ind=0;    memset(dfn,0,sizeof(dfn));    for (int i=1;i<=2*N;i++)        if (!dfn[i]) tarjan(i);}int main(){    //freopen("/home/christinass/code/in.txt","r",stdin);    int cas,k,t;    scanf("%d",&cas);    for (int h=1;h<=cas;h++)    {        scanf("%d%d",&n,&m);        ecnt=0;        N=max(n,m);        memset(g,0,sizeof(g));        memset(pre,-1,sizeof(pre));        for (int i=1;i<=n;i++)        {            scanf("%d",&k);            for (int j=1;j<=k;j++)            {                scanf("%d",&t);                g[i][t]=1;            }        }        int ans=hungry();        memset(to,0,sizeof(to));        n2=n,m2=m;        if (ans<n||ans<m)        {            for (int i=1;i<=m;i++)                to[result[i]]=i;            for (int i=1;i<=n;i++)                if (!to[i])                {                    ++m2;                    for (int j=1;j<=n;j++) g[j][m2]=1;                }            for (int i=1;i<=m;i++)                if (!result[i])                {                    ++n2;                    for (int j=1;j<=m;j++) g[n2][j]=1;                }        }        swap(n,n2);swap(m,m2);        N=hungry();        for (int i=1;i<=N;i++)        {            int u=result[i];            to[u]=i;            for (int j=1;j<=N;j++)                if (g[u][j]&&j!=i)                    add(i,j);        }        printf("Case #%d:\n",h);        solve();        for (int i=1;i<=n2;i++)        {            int u=to[i],cnt=0;            for (int j=1;j<=m2;j++)                if (g[i][j]&&bel[u]==bel[j]) tmp[cnt++]=j;            printf("%d%s",cnt,cnt?" ":"\n");            for (int j=0;j<cnt;j++)                printf("%d%s",tmp[j],j+1==cnt?"\n":" ");        }    }    return 0;}


原创粉丝点击