题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685

题意:给出n个王子和m个公主。每个王子有一些自己喜欢的公主可以匹配。设最大匹配为M。那么对于每个王子,可以选择哪些自己喜欢的公主使得选择之后最大匹配仍为M?

思路:(1)首先,想到的一个方法是先求一次最大匹配。然后枚举每个王子喜欢的公主作为该王子的匹配,判断能否为之前匹配该公主的王子重新找到一个匹配。这样的复杂付太大。

(2)改进:做法是先求一次最大匹配设为cnt,那么左边有n-cnt个王子还未匹配,右边有m-cnt个公主还未匹配,因此我们将左侧增加m-cnt个虚拟王子,虚拟王子与右边所有公主连边;右边增加n-cnt个虚拟公主,虚拟公主与左边所有王子连边,这样我们就得到一个两边各有M=n+m-cnt的二分图,且该二分图是一个完美匹配。也就是每个王子都有一个匹配的公主。现在,我们将每个王子匹配的公主向该王子喜欢的公主连边(建一个新图g),然后求g的强连通分量。那么与每个王子之前匹配的公主在一个强连通分量里的公主都可以作为该王子的匹配使得最大匹配不变。为什么是这样的呢?我们想想(1)中的方法,设王子i之前的匹配为p[i],现在为王子i选择一个新的公主j,那么我们若能为p[i]重新找到一个王子k,那么实质上就是找到另一个王子互换两个两个王子喜欢的公主。因此两公主若在一个强连通分量里,那么王子由之前的匹配公主A选择公主B时,A也能找到另一个匹配,因为B能够通过某些路径到达A,等价于这条环上所有王子的匹配都后移一个人而已。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <map>
#include <ctype.h>
#include <time.h>

#define abs(x) ((x)>=0?(x):-(x))
#define i64 long long
#define u32 unsigned int
#define u64 unsigned long long
#define clr(x,y) memset(x,y,sizeof(x))
#define CLR(x) x.clear()
#define ph(x) push(x)
#define pb(x) push_back(x)
#define Len(x) x.length()
#define SZ(x) x.size()
#define PI acos(-1.0)
#define sqr(x) ((x)*(x))
#define MP(x,y) make_pair(x,y)
#define EPS 1e-10

#define FOR0(i,x) for(i=0;i<x;i++)
#define FOR1(i,x) for(i=1;i<=x;i++)
#define FOR(i,a,b) for(i=a;i<=b;i++)
#define FORL0(i,a) for(i=a;i>=0;i--)
#define FORL1(i,a) for(i=a;i>=1;i--)
#define FORL(i,a,b)for(i=a;i>=b;i--)

#define rush() int CC;for(scanf("%d",&CC);CC--;)
#define Rush(n)  while(scanf("%d",&n)!=-1)
using namespace std;

void RD(int &x){scanf("%d",&x);}
void RD(i64 &x){scanf("%I64d",&x);}
void RD(u64 &x){scanf("%I64u",&x);}
void RD(u32 &x){scanf("%u",&x);}
void RD(double &x){scanf("%lf",&x);}
void RD(int &x,int &y){scanf("%d%d",&x,&y);}
void RD(i64 &x,i64 &y){scanf("%lld%lld",&x,&y);}
void RD(u32 &x,u32 &y){scanf("%u%u",&x,&y);}
void RD(double &x,double &y){scanf("%lf%lf",&x,&y);}
void RD(double &x,double &y,double &z){scanf("%lf%lf%lf",&x,&y,&z);}
void RD(int &x,int &y,int &z){scanf("%d%d%d",&x,&y,&z);}
void RD(i64 &x,i64 &y,i64 &z){scanf("%lld%lld%lld",&x,&y,&z);}
void RD(u32 &x,u32 &y,u32 &z){scanf("%u%u%u",&x,&y,&z);}
void RD(char &x){x=getchar();}
void RD(char *s){scanf("%s",s);}
void RD(string &s){cin>>s;}

void PR(int x) {printf("%d\n",x);}
void PR(int x,int y) {printf("%d %d\n",x,y);}
void PR(i64 x) {printf("%lld\n",x);}
void PR(i64 x,i64 y) {printf("%lld %lld\n",x,y);}
void PR(u32 x) {printf("%u\n",x);}
void PR(u64 x) {printf("%llu\n",x);}
void PR(double x) {printf("%.3lf\n",x);}
void PR(double x,double y) {printf("%.5lf %.5lf\n",x,y);}
void PR(char x) {printf("%c\n",x);}
void PR(char *x) {printf("%s\n",x);}
void PR(string x) {cout<<x<<endl;}

void upMin(int &x,int y) {if(x>y) x=y;}
void upMin(i64 &x,i64 y) {if(x>y) x=y;}
void upMin(double &x,double y) {if(x>y) x=y;}
void upMax(int &x,int y) {if(x<y) x=y;}
void upMax(i64 &x,i64 y) {if(x<y) x=y;}
void upMax(double &x,double y) {if(x<y) x=y;}

const int mod=1000000007;
const i64 inf=((i64)1)<<60;
const double dinf=1000000000000000000.0;
const int INF=100000000;
const int N=1005;

vector<int> g[N],ans[N];

int dfn[N],low[N],visit[N],num,id,color[N];
stack<int> S;

int n,m;
int G[N][N];
int match[N],X,p[N];
int M;

int DFS(int u)
{
    int i;
    FOR1(i,M) if(G[u][i]&&X!=visit[i])
    {
        visit[i]=X;
        if(match[i]==-1||DFS(match[i]))
        {
            match[i]=u;
            p[u]=i;
            return 1;
        }
    }
    return 0;
}

void dfs(int u)
{
    dfn[u]=low[u]=++id;
    S.push(u);
    int i,v;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i];
        if(!dfn[v])
        {
            dfs(v);
            upMin(low[u],low[v]);
        }
        else if(X!=visit[v])
        {
            upMin(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u])
    {
        num++;
        do
        {
            v=S.top();
            S.pop();
            visit[v]=X;
            color[v]=num;
        }while(u!=v);
    }
}

int main()
{
    int Num=0;
    rush()
    {
        RD(n,m);
        int i,j,k,x;

        clr(G,0);
        FOR1(i,n)
        {
            RD(k);
            while(k--) RD(x),G[i][x]=1;
        }    

        clr(match,-1); clr(p,-1);
        int cnt=0;
        M=m;
        FOR1(i,n) X++,cnt+=DFS(i);
        M=n+m-cnt;
        for(i=n+1;i<=M;i++) FOR1(j,M) G[i][j]=1;
        for(i=m+1;i<=M;i++) FOR1(j,M) G[j][i]=1;
        clr(match,-1); clr(p,-1);
        FOR1(i,M) X++,DFS(i);
        FOR1(i,M) g[i].clear(),ans[i].clear();

        FOR1(i,M)
        {
            FOR1(j,M) if(p[i]!=j&&G[i][j])
            {
                g[p[i]].pb(j);
            }
        }
        clr(dfn,0); X++; id=num=0;
        FOR1(i,M) if(!dfn[i]) dfs(i);
        FOR1(i,n) FOR1(j,m) if(G[i][j]&&color[j]==color[p[i]])
        {
            ans[i].pb(j);
        }
        printf("Case #%d:\n",++Num);
        FOR1(i,n)
        {
            printf("%d",(int)SZ(ans[i]));
            FOR0(k,SZ(ans[i])) printf(" %d",ans[i][k]);
            puts("");
        }
    }
}

  

HDU 4685 Prince and Princess(二分图+强连通分量)的更多相关文章

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

    Prince and Princess 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 Description There are n pri ...

  2. HDU 4685 Prince and Princess (2013多校8 1010题 二分匹配+强连通)

    Prince and Princess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Othe ...

  3. HDU 4685 Prince and Princess

    强连通分量,看大神的题解才会写的.... http://www.cnblogs.com/kuangbin/p/3261157.html 数据量有点大,第一次Submit 2995ms过的,时限3000 ...

  4. HDU 4685 Prince and Princess(二分匹配+强联通分量)

    题意:婚配问题,但是题目并不要求输出最大匹配值,而是让我们输出,一个王子可以与哪些王妃婚配而不影响最大匹配值. 解决办法:先求一次最大匹配,如果有两个已经匹配的王妃,喜欢她们两个的有两个或者以上相同的 ...

  5. hdu 4685 Prince and Princess(匈牙利算法 连通分量)

    看了别人的题解.须要用到匈牙利算法的强连通算法 #include<cstdio> #include<algorithm> #include<vector> #pra ...

  6. HDU 3861 The King’s Problem 强连通分量 最小路径覆盖

    先找出强连通分量缩点,然后就是最小路径覆盖. 构造一个二分图,把每个点\(i\)拆成两个点\(X_i,Y_i\). 对于原图中的边\(u \to v\),在二分图添加一条边\(X_u \to Y_v\ ...

  7. HDU4685 Prince and Princess【强连通】

    题意: 有n个王子和m个公主,每个王子都会喜欢若干个公主,也就是王子只跟自己喜欢的公主结婚,公主就比较悲惨, 跟谁结婚都行.然后输出王子可能的结婚对象,必须保证王子与任意这些对象中的一个结婚,都不会影 ...

  8. hdu 4685(强连通分量+二分图)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685 题意:n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能 ...

  9. hdu 4685(强连通分量+二分图的完美匹配)

    传送门:Problem 4685 https://www.cnblogs.com/violet-acmer/p/9739990.html 参考资料: [1]:二分图的最大匹配.完美匹配和匈牙利算法 [ ...

随机推荐

  1. tcp-client-c++

    #include "stdafx.h" #include <Winsock2.h> #include <iostream> #pragma comment( ...

  2. 阿里云mysql数据库恢复总结,mysql binlog日志解析

    由于意外..阿里云mysql中有一张表被全部删除了,深吸三口气候,开始解决. 首先用凌晨的自动备份的,进行全量恢复,然后找binlog日志(见下文),查找从全量备份到数据删除之间的记录 这导致了一个问 ...

  3. Xcode8兼容iOS7手记-b

    对于Xcode8的发布,苹果也是来了个大的跳跃,默认最低支持的iOS版本为8.0,当然也并不是说8.0以下就直接放弃了,虽然表现出来的是这样,毕竟使用8.0以下系统的还是大有人在的,老项目要兼容iOS ...

  4. 【转】如何设置Android软键盘的默认不弹出?

    在开发Anroid的时候,当你打开一个界面的时候,屏幕的焦点会自动停留在第一个EditText中,Android的软键盘默认会自动弹出,用户第一眼连界面都没有看清楚,软键盘就弹出来了,这就影响到了用户 ...

  5. python 获取文件大小,创建时间和访问时间

    # -*- coding: UTF8 -*- import timeimport datetime import os 1. '''把时间戳转化为时间: 1479264792 to 2016-11-1 ...

  6. Android Bluetooth Stream Non-blocking Communication Tutorial

    This is a tutorial for Android to do non-blocking bluetooth socket communication. I am using 32feet ...

  7. iOS Core data多线程并发访问的问题

    大家都知道Core data本身并不是一个并发安全的架构:不过针对多线程访问带来的问题,Apple给出了很多指导:同时很多第三方的开发者也贡献了很多解决方法.不过最近碰到的一个问题很奇怪,觉得有一定的 ...

  8. uva 11375

    思路是刘书上的 但是个高精度  java 大数 ~~ import java.util.*; import java.io.*; import java.math.BigInteger; public ...

  9. Unity3D脚本中文系列教程(一)

    原地址:http://dong2008hong.blog.163.com/blog/static/46968827201403115643431/?suggestedreading&wumii ...

  10. html添加keyword,description帮助百度收录处理方法,jsp去除空白行方法

    1.将网页的title,keyword,description写成include包含文件,例如: top.jsp <%@ page language="java" conte ...