HDU 4685 Prince and Princess 二分图匹配+tarjan

Prince and Princess

题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=4685

Description

There are n princes and m princesses. Princess can marry any prince. But prince can only marry the princess they DO love.
For all princes,give all the princesses that they love. So, there is a maximum number of pairs of prince and princess that can marry.
Now for each prince, your task is to output all the princesses he can marry. Of course if a prince wants to marry one of those princesses,the maximum number of marriage pairs of the rest princes and princesses cannot change.

Input

The first line of the input contains an integer T(T<=25) which means the number of test cases.
For each test case, the first line contains two integers n and m (1<=n,m<=500), means the number of prince and princess.
Then n lines for each prince contain the list of the princess he loves. Each line starts with a integer ki(0<=ki<=m), and then ki different integers, ranging from 1 to m denoting the princesses.

Output

For each test case, first output "Case #x:" in a line, where x indicates the case number between 1 and T.
Then output n lines. For each prince, first print li, the number of different princess he can marry so that the rest princes and princesses can still get the maximum marriage number.
After that print li different integers denoting those princesses,in ascending order.

Sample Input

2
4 4
2 1 2
2 1 2
2 2 3
2 3 4
1 2
2 1 2

Sample Output

Case #1:
2 1 2
2 1 2
1 3
1 4
Case #2:
2 1 2

Hint

题意

有n个王子,m个公主

每个王子喜欢ki个公主,现在把每个王子喜欢的公主都给了出来

国王叫大臣制作一张表,输出每个王子和这个公主结婚之后,满足不会影响别人结婚的条件

如果这个王子和这个公主结婚之后,依旧是一个完备匹配的话,就输出

题解:

和poj 1904不一样的是,这道题并没有给出完备匹配,而且男女人数不相等

这一点的话,我们可以先求一个二分图的最大匹配之后,假设匹配数是cnt

那么把左右两边的点都补充为n+m-cnt个点,然后再跑二分图

跑完之后就可以得到完备匹配了,然后就和1904做法一样了。

空间注意开大一点,不然会迷之wa……

不过我的做法不一样,我后面跑tarjan的时候,是让公主之间连边,让这个王子匹配的公主,和他喜欢的公主连边

然后跑的tarjan

代码

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 3e3+6;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,k,dfn[maxn],low[maxn],_clock=0,sta[maxn],top;
bool in_sta[maxn];
int changed[maxn],scc,num[maxn],vis[maxn],Left[maxn],Rht[maxn],mp[1005][1005];
vector<int> E[maxn],G[maxn];
vector<int>lft[maxn];
vector<int> ans;
void init()
{
    memset(Rht,0,sizeof(Rht));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(sta,0,sizeof(sta));
    memset(in_sta,0,sizeof(in_sta));
    memset(changed,0,sizeof(changed));
    memset(num,0,sizeof(num));
    memset(vis,0,sizeof(vis));
    memset(mp,0,sizeof(mp));
    memset(Left,-1,sizeof(Left));
    for(int i=0;i<maxn;i++)E[i].clear(),G[i].clear();
    for(int i=0;i<maxn;i++)lft[i].clear();
    scc=0;top=0;_clock=0;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++_clock;
    sta[++top]=x;
    in_sta[x]=1;
    for(int i=0;i<E[x].size();i++)
    {
        int v = E[x][i];
        if(!dfn[v])
            tarjan(v),low[x]=min(low[x],low[v]);
        else if(in_sta[v])
            low[x]=min(low[x],dfn[v]);
    }
    if(dfn[x]==low[x])
    {
        int temp;
        ++scc;
        do{
            temp = sta[top--];
            in_sta[temp]=0;
            changed[temp]=scc;
            ++num[scc];
        }while(temp!=x);
    }
}
void add(int x,int y)
{
    lft[x].push_back(y);
}
int dfs2(int x){
    for(int i=0;i<lft[x].size();i++){
        int it=lft[x][i];
        if(Left[it] == -1){
            Left[it] = x;
            Rht[x]=it;
            return 1;
        }
        if(vis[it]) continue;
        vis[it] = 1;
        if(dfs2(Left[it])){
            Left[it] = x;
            Rht[x]=it;
            return 1;
        }
    }
    return 0;
}
void solve(int cas)
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int x=read();
        for(int j=0;j<x;j++)
        {
            int y=read();
            add(i,n+y);
            G[i].push_back(y);
        }
    }
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        cnt+=dfs2(i);
    }
    for(int i=0;i<maxn;i++)lft[i].clear();
    memset(Left,-1,sizeof(Left));
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<G[i].size();j++)
        {
            mp[i][G[i][j]]=1;
            add(i,n+m-cnt+G[i][j]);
        }
    }
    for(int i=n+1;i<=n+m-cnt;i++)
    {
        for(int j=1;j<=n+m-cnt;j++)
        {
            mp[i][j]=1;
            add(i,n+m-cnt+j);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=m+1;j<=n+m-cnt;j++)
        {
            mp[i][j]=1;
            add(i,n+m-cnt+j);
        }
    }
    for(int i=1;i<=n+m-cnt;i++)
    {
        memset(vis,0,sizeof(vis));
        dfs2(i);
    }
    for(int i=1;i<=n+m-cnt;i++)
    {
        for(int j=1;j<=n+m-cnt;j++)
        {
            if(Rht[i]-n-m+cnt!=j&&mp[i][j])
                E[Rht[i]-n-m+cnt].push_back(j);
        }
    }
    for(int i=1;i<=(n+m-cnt);i++)
        if(!dfn[i])tarjan(i);
    printf("Case #%d:\n",cas);
    for(int i=1;i<=n;i++)
    {
        ans.clear();
        for(int j=1;j<=m;j++)
        {
            if(mp[i][j]&&changed[Rht[i]-n-m+cnt]==changed[j])
                ans.push_back(j);
        }
        printf("%d",ans.size());
        for(int j=0;j<ans.size();j++)
            printf(" %d",ans[j]);
        printf("\n");
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
        solve(i);
    return 0;
}

你可能感兴趣的:(HDU 4685 Prince and Princess 二分图匹配+tarjan)