【hdu】4685 Prince and Princess【二分匹配+tarjan】

来源:互联网 发布:通讯软件排名 编辑:程序博客网 时间:2024/05/16 05:58

题意:有n个王子,m个公主,每个王子有他自己喜欢的公主们,问一个王子可以匹配的公主有哪些,要求一个王子匹配一个公主后,总的可匹配数不能减少,也就是不能让别的王子的本来可以有老婆的,现在没了。

题解:题意和poj1904集合一样,只不过那题给出了完美匹配,且王子与公主都是n个,这题又加了限制,是poj1904的加强版,可以先试试那题再来做这题后好理解很多,这是poj1904的题解 http://blog.csdn.net/a709743744/article/details/52133778

现在我们在上述题解的情况下继续讲这题怎么做,我们把这题尽量转换成poj1904的形式,我们先对题目给出的条件求一次二分匹配,

假设匹配数是cnt,

对于未匹配的n-cnt个王子,我们虚拟出n-cnt个公主和他匹配,并让所有真实王子都喜欢这个虚拟公主

对于未匹配的m-cnt个公主,我们虚拟出m-cnt个王子和她匹配,并让虚拟王子喜欢所有的真实公主

这样王子和公主都有n+m-cnt个,问题就完全转换成了poj1904,然后我们就按poj1904求一遍强连通,记得最后别输出虚拟公主即可

#include<queue>#include<vector>#include<cstdio>//先用强连通缩点来化简图,然后在图上做拓扑排序,如果排序过程中,出现1个以上的点入度同时为0时,那么就不满足条件。#include<cstring>#include<algorithm>#define PB push_back#define MP make_pairusing namespace std;const int N=4010;const int inf=0x3f3f3f3f;int dfn[N],low[N],instack[N],belong[N],S[N];int index,scc,shead;vector<int>G[N];vector<pair<int,int> >E[N];void dfs(int u){    dfn[u]=low[u]=++index;    S[shead++]=u;    instack[u]=true;    for(int i=0;i<G[u].size();i++){        int v=G[u][i];        if(!dfn[v]){            dfs(v);            low[u]=min(low[v],low[u]);        }else if(instack[v])            low[u]=min(dfn[v],low[u]);    }    if(low[u]==dfn[u]){        scc++;        while(1){            int tmp=S[--shead];            belong[tmp]=scc;            instack[tmp]=false;            if(tmp==u)break;        }    }}void tarjan(int n){    index=scc=shead=0;    memset(dfn,0,sizeof(dfn));    memset(instack,false,sizeof(instack));    for(int i=1;i<=n;i++)if(!dfn[i])dfs(i);}int ans[N],lx[N],ly[N],used[N],n,m;bool Dfs(int u){    for(int i=0;i<G[u].size();i++){        int v=G[u][i];        if(!used[v]){            used[v]=true;            if(ly[v]==-1||Dfs(ly[v])){                ly[v]=u;                lx[u]=v;                return true;            }        }    }    return false;}int hungry(int n){    int res=0;    memset(lx,-1,sizeof(lx));    memset(ly,-1,sizeof(ly));    for(int i=1;i<=n;i++){        memset(used,0,sizeof(used));        if(Dfs(i))res++;    }    return res;}int main(){    int T,kase=0;    scanf("%d",&T);    while(T--){        scanf("%d%d",&n,&m);        for(int i=1;i<=(n+m)*2;i++)G[i].clear();        for(int i=1;i<=n;i++){            int x,y;            scanf("%d",&x);            while(x--){                scanf("%d",&y);                G[i].PB(n+y);            }        }        hungry(n);        int all=n+m;        for(int i=1;i<=n;i++)if(lx[i]==-1){//新增妹子            all++;            lx[i]=all;            ly[all]=i;            for(int j=1;j<=n;j++)G[j].PB(all);        }        for(int j=1;j<=m;j++)if(ly[j+n]==-1){//新增王子            all++;            lx[all]=j+n;            ly[j+n]=all;            for(int j=1;j<=m;j++)G[all].PB(j+n);        }        for(int i=1;i<=all;i++)            if(lx[i]!=-1)G[lx[i]].PB(i);        tarjan(all);        printf("Case #%d:\n",++kase);        for(int i=1;i<=n;i++){            int cnt=0;            for(int j=0;j<G[i].size();j++){                int v=G[i][j];                if(belong[i]==belong[v]){                    if(v-n<=m)ans[cnt++]=v-n;                }            }            sort(ans,ans+cnt);            printf("%d",cnt);            for(int j=0;j<cnt;j++){                printf(" %d",ans[j]);            }            printf("\n");        }    }    return 0;}


0 0