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

思路:想了好久,终于想明白了,懒得写了,直接copy大牛的思路了,写的非常好!

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

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
#define MAXN 1111 int n,m,N,cnt;
bool map[MAXN][MAXN];
bool mark[MAXN];
int ly[MAXN];
int lx[MAXN]; int dfs(int u,int m)
{
for(int v=;v<=m;v++){
if(map[u][v]&&!mark[v]){
mark[v]=true;
if(ly[v]==-||dfs(ly[v],m)){
ly[v]=u;
lx[u]=v;
return ;
}
}
}
return ;
} int MaxMatch(int n,int m)
{
memset(ly,-,sizeof(ly));
memset(lx,-,sizeof(lx));
int ans=;
for(int i=;i<=n;i++){
memset(mark,false,sizeof(mark));
ans+=dfs(i,m);
}
return ans;
} vector<vector<int> >g;
vector<vector<int> >ans; int dfn[MAXN],low[MAXN];
int color[MAXN],_count;
stack<int>S; void Tarjan(int u)
{
low[u]=dfn[u]=++cnt;
mark[u]=true;
S.push(u);
for(int i=;i<g[u].size();i++){
int v=g[u][i];
if(dfn[v]==){
Tarjan(v);
low[u]=min(low[u],low[v]);
}else if(mark[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
_count++;
int x;
do{
x=S.top();
S.pop();
mark[x]=false;
color[x]=_count;
}while(x!=u);
}
} int main()
{
int _case,k,x,t=;
scanf("%d",&_case);
while(_case--){
scanf("%d%d",&n,&m);
memset(map,false,sizeof(map));
for(int i=;i<=n;i++){
scanf("%d",&k);
while(k--){
scanf("%d",&x);
map[i][x]=true;
}
}
cnt=MaxMatch(n,m);
N=n+m-cnt;
for(int i=n+;i<=N;i++)
for(int j=;j<=N;j++)
map[i][j]=true;
for(int i=m+;i<=N;i++)
for(int j=;j<=N;j++)
map[j][i]=true;
MaxMatch(N,N);
g.clear();
g.resize(N+);
ans.clear();
ans.resize(N+);
for(int i=;i<=N;i++){
for(int j=;j<=N;j++){
if(lx[i]!=j&&map[i][j]){
g[lx[i]].push_back(j);
}
}
}
memset(dfn,,sizeof(dfn));
memset(mark,false,sizeof(mark));
_count=cnt=;
for(int i=;i<=N;i++)
if(dfn[i]==)Tarjan(i);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(map[i][j]&&color[lx[i]]==color[j]){
ans[i].push_back(j);
}
}
}
printf("Case #%d:\n",t++);
for(int i=;i<=n;i++){
printf("%d",(int)ans[i].size());
for(int j=;j<ans[i].size();j++){
printf(" %d",ans[i][j]);
}
puts("");
}
}
return ;
}

hdu 4685(匹配+强连通分量)的更多相关文章

  1. HDU 3639 Hawk-and-Chicken(强连通分量+缩点)

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u013480600/article/details/32140501 HDU 3639 Hawk-a ...

  2. poj1904 二分图匹配+强连通分量

    http://poj.org/problem?id=1904 Description Once upon a time there lived a king and he had N sons. An ...

  3. hdu 4685 二分匹配+强连通分量

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 题解: 这一题是poj 1904的加强版,poj 1904王子和公主的人数是一样多的,并且给出 ...

  4. UESTC 898 方老师和缘分 --二分图匹配+强连通分量

    这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u-> ...

  5. H - Prince and Princess - HDU 4685(二分匹配+强连通分量)

    题意:有N个王子M个公主,王子喜欢一些公主,而且只能是王子喜欢的人,他们才可以结婚,现在让他们尽可能多的结婚的前提下找出来每个王子都可以和谁结婚. 分析:先求出来他们的最大匹配,因为给的数据未必是完备 ...

  6. Luogu3731 HAOI2017新型城市化(二分图匹配+强连通分量)

    将未建立贸易关系看成连一条边,那么这显然是个二分图.最大城市群即最大独立集,也即n-最大匹配.现在要求的就是删哪些边会使最大匹配减少,也即求哪些边一定在最大匹配中. 首先范围有点大,当然是跑个dini ...

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

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

  8. HDU 4685 Prince and Princess(二分图+强连通分量)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685 题意:给出n个王子和m个公主.每个王子有一些自己喜欢的公主可以匹配.设最大匹配为M.那么对于每个 ...

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

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

随机推荐

  1. Java之Undeclared Checked Exception

    之前一直认为在Java里如果每个task是相对独立.并且是可以容忍错误的,那么只需要处理Checked Exception(这个是Java强制的)和主动处理Unchecked Exception(派生 ...

  2. 【CentOS6.5】MySQL安装和配置

    1./etc/my.cnf 这是mysql的主配置文件 2.数据存放位置 3.错误存放位置

  3. Docker实战(五)编写Dockerfile

    一.创建Dockerfile文件 首先,需要创建一个目录来存放 Dockerfile 文件,目录名称可以任意,在目录里创建Dockerfile文件: 二.Dockerfile 基本框架 Dockerf ...

  4. python --文本文件的输入输出

    转自:http://www.cnblogs.com/vamei/archive/2012/06/06/2537868.html Python具有基本的文本文件读写功能.Python的标准库提供有更丰富 ...

  5. C#:将空间数据加载到树视图控件

    自己 整理了 下 代码 测试了下 还行... #region 操作树视图控件 /// <summary> /// 自定义需要的类型 /// </summary> enum Da ...

  6. Mockito 相关资料

    https://monkeyisland.pl/2008/04/26/asking-and-telling/ http://qiuguo0205.iteye.com/blog/1456528 http ...

  7. unity, 查看资源文件类型

  8. Redis(十五):哨兵Sentinel

    Redis哨兵 Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务: 监控(Monitoring): Sentinel 会不断地检查你 ...

  9. 【iOS开发之Objective-C】书签管理器项目

    1.项目 新建一个书签管理器的项目,能够存储书签的网址.中文名.星级.訪问量和权限信息.具有增.删.改.查和排序的功能. 2.找对象,抽象类 书签管理器,书签管理器.书签管理器--  多读几次书是不是 ...

  10. C++ 模板详解 肥而不腻

    C++模板 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有 ...