hdu 4685(强连通分量+二分图的完美匹配)
https://www.cnblogs.com/violet-acmer/p/9739990.html
参考资料:
[2]:http://www.cnblogs.com/frog112111/p/3387173.html
题意:
n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能的结婚对象。
必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了。
分析:
这题是poj 1904的加强版,poj 1904的王子和公主数是相等的,这里可以不等,且poj 1904给出了一个初始完美匹配,但是这题就要自己求。
所以只要求出完美匹配之后,就和poj 1904的做法就完全相同了。
那么怎么求出完美匹配呢?一开始我用多重匹配的匈牙利算法来做,但是怎么做都不对.......看了题解才恍然大悟=_=
先说几个坑,这题有点奇怪,就是所有王子都可以争着和同一个公主结婚,只要该王子喜欢该公主,感觉公主有点悲哀呀........
比如:
2 2
1 1
1 1
输出的答案是:
1 1
1 1
而不是
1 1
0
这里就是和poj 1904有点不一样的地方,坑了我好久.........
求完美匹配:
先对原图用匈牙利算法做一遍二分图匹配,但是还有可能剩余一些人还没匹配,只要虚拟出一些节点来匹配剩余的点就行了。
假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。
假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主
这样就构成完美匹配了,接下来就是和poj 1904一样了。
AC代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define pb push_back
#define mem(a,b) memset(a,b,sizeof a)
const int maxn=+++; int n,m;
//===========匈牙利===========
struct Node
{
int matchM[maxn];
int matchW[maxn];
bool check[maxn];
vector<int >edge[maxn];
void Init()
{
mem(matchM,-);
mem(matchW,-);
for(int i=;i < maxn;++i)
edge[i].clear();
}
void addEdge(int u,int v){
edge[u].pb(v);
}
bool Dfs(int u)
{
for(int i=;i < edge[u].size();++i)
{
int to=edge[u][i];
if(!check[to])
{
check[to]=true;
if(matchW[to] == - || Dfs(matchW[to]))
{
matchW[to]=u;
matchM[u]=to;
return true;
}
}
}
return false;
}
void Hungarian()
{
for(int i=;i <= n;++i)
{
mem(check,false);
Dfs(i);
}
}
}_match;
//============================
//============SCC=============
int scc[maxn];
bool vis[maxn];
vector<int >vs;
vector<int >edge[maxn],redge[maxn];
void addEdge(int u,int v)
{
edge[u].pb(v);
redge[v].pb(u);
}
void Dfs(int u)
{
vis[u]=true;
for(int i=;i < edge[u].size();++i)
{
int to=edge[u][i];
if(!vis[to])
Dfs(to);
}
vs.pb(u);
}
void rDfs(int u,int sccId)
{
scc[u]=sccId;
vis[u]=true;
for(int i=;i < redge[u].size();++i)
{
int to=redge[u][i];
if(!vis[to])
rDfs(to,sccId);
}
}
void Scc()
{
mem(vis,false);
vs.clear();
for(int i=;i <= n;++i)
if(!vis[i])
Dfs(i);
mem(vis,false);
int sccId=;
for(int i=vs.size()-;i >= ;--i)
{
int to=vs[i];
if(!vis[to])
rDfs(to,++sccId);
}
}
//============================
void Init()
{
_match.Init();
for(int i=;i < maxn;++i)
edge[i].clear(),redge[i].clear();
}
int main()
{
int T;
scanf("%d",&T);
for(int kase=;kase <= T;++kase)
{
Init();
scanf("%d%d",&n,&m);
for(int i=;i <= n;++i)
{
int k;
scanf("%d",&k);
while(k--)
{
int v;
scanf("%d",&v);
addEdge(i,v+n);
_match.addEdge(i,v+n);
}
}
_match.Hungarian();//匈牙利算法求最大匹配
int all=n+m;
for(int i=;i <= n;++i)
{
if(_match.matchM[i] == -)//为剩余王子匹配虚拟公主
{
all++;
for(int j=;j <= n;++j)//所有王子都喜欢该虚拟公主
addEdge(j,all);
_match.matchM[i]=all;
_match.matchW[all]=i;
}
}
for(int i=n+;i <= n+m;++i)
{
if(_match.matchW[i] == -)//为剩余公主匹配虚拟王子
{
all++;
for(int j=n+;j <= n+m;++j)//该虚拟王子喜欢所有公主
addEdge(all,j);
_match.matchM[all]=i;
_match.matchW[i]=all;
}
}
for(int i=;i <= all;++i)
if(_match.matchM[i] != -)//所有与王子匹配的公主建一条边连向王子
addEdge(_match.matchM[i],i);
Scc();//求强连通分量
printf("Case #%d:\n",kase);
for(int i=;i <= n;++i)
{
int res=;
int ans[maxn];
for(int j=;j < edge[i].size();++j)
{
int to=edge[i][j];
if(scc[i] == scc[to] && to <= m+n)//剔除掉虚拟的公主
ans[res++]=to-n;
}
sort(ans,ans+res);
printf("%d",res);
for(int i=;i < res;++i)
printf(" %d",ans[i]);
printf("\n");
}
}
}
Kosaraju算法
hdu 4685(强连通分量+二分图的完美匹配)的更多相关文章
- hdu 4685(强连通分量+二分图)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685 题意:n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能 ...
- POJ 1904 King's Quest ★(强连通分量:可行完美匹配边)
题意 有n个女生和n个男生,给定一些关系表示男生喜欢女生(即两个人可以结婚),再给定一个初始匹配,表示这个男生和哪个女生结婚,初始匹配必定是合法的.求每个男生可以和哪几个女生可以结婚且能与所有人不发生 ...
- (step6.3.5)hdu 1281(棋盘游戏——二分图的完美匹配)
题目大意:本体是中文题.读者可以直接在OJ上看 解题思路: 1)完美匹配:所有的端点都是匹配点 2)对于二分图的完美匹配,我们需要用一个数组来存储匹配点.(而二分图的其他问题(我们则可以直接使用变量来 ...
- codevs 1222 信与信封问题(二分图的完美匹配)
1222 信与信封问题 题目描述 Description John先生晚上写了n封信,并相应地写了n个信封将信装好,准备寄出.但是,第二天John的儿子Small John将这n封信都拿出了信封. ...
- UVa1349 Optimal Bus Route Design(二分图最佳完美匹配)
UVA - 1349 Optimal Bus Route Design Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & ...
- UVa 11383 少林决胜(二分图最佳完美匹配)
https://vjudge.net/problem/UVA-11383 题意: 给定一个N×N矩阵,每个格子里都有一个正整数W(i,j).你的任务是给每行确定一个整数row(i),每列也确定一个整数 ...
- Ants(二分图最佳完美匹配)
Ants Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 6904 Accepted: 2164 Special Ju ...
- UVA - 1045 The Great Wall Game(二分图最佳完美匹配)
题目大意:给出棋盘上的N个点的位置.如今问将这些点排成一行或者一列.或者对角线的最小移动步数(每一个点都仅仅能上下左右移动.一次移动一个) 解题思路:暴力+二分图最佳完美匹配 #include < ...
- HDU 3072 (强连通分量)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3072 题目大意:为一个有向连通图加边.使得整个图全连通,有重边出现. 解题思路: 先用Tarjan把 ...
随机推荐
- ecna2017-Game of Throwns
这题就是给你一个标号为0-n-1的环,然后给你M个操作,操作有两种,一种是直接给一个数,这数的正负代表我当前向前(向后)仍了xx个位置的球,或者给你一个撤销操作表示为 undo m,表示撤销最近的M个 ...
- 如何在css中设置按钮button中包含图片文字对齐方式
<el-button class="class-management style="line-heught">班级管理
- 《linux内核设计与实现》第四章
调度程序负责决定哪个进程投入运行,何时运行以及运行多长时间.只有通过调度程序合理调度,系统资源才能最大限度发挥作用,多进程才会有并发执行的效果. 最大限度地利用处理器时间的原则是,只要有可以执行的进程 ...
- 读书笔记(chapter4)
进程调度 4.1多任务 1.多任务系统可以划分为:非抢占式多任务和抢占式多任务: (在此模式下,由调度程序来决定什么时候停止一个进程的运行,以便其他进程能够得到执行机会,这个动作叫抢占: 时间片实际上 ...
- HDU 2012 素数判定
http://acm.hdu.edu.cn/showproblem.php?pid=2012 Problem Description 对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括 ...
- CAS的应用场景
国外应用(需FQ尝试): 来自CAS官网推荐的Demo http://casserver.herokuapp.com/cas/login https://casserver.herokuapp.com ...
- FreeMarker has_content等价于StringUtils.isNotNullOrEmpty
has_content It is true if the variable exists (and isn't Java null) and is not "empty", ot ...
- Linux安装的分区问题
对于一般的外部SATA存储设备,在ubuntu中会显示在/etc/sd*中,例如: SATA1插槽上的文件名:/dev/sda SATA5插槽上的文件名:/dev/sdb USB磁盘:/dev/sdc ...
- apache Storm学习之二-基本概念介绍
2.1 Storm基本概念 在运行一个Storm任务之前,需要了解一些概念: Topologies Streams Spouts Bolts Stream groupings Reliability ...
- Java和Android的Lru缓存,及其实现原理
一.概述 Android提供了LRUCache类,可以方便的使用它来实现LRU算法的缓存.Java提供了LinkedHashMap,可以用该类很方便的实现LRU算法,Java的LRULinkedHas ...