HDU 4685 Prince and Princess(二分图+强连通分量)
题目链接: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(二分图+强连通分量)的更多相关文章
- HDU 4685 Prince and Princess 二分图匹配+tarjan
Prince and Princess 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 Description There are n pri ...
- 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 ...
- HDU 4685 Prince and Princess
强连通分量,看大神的题解才会写的.... http://www.cnblogs.com/kuangbin/p/3261157.html 数据量有点大,第一次Submit 2995ms过的,时限3000 ...
- HDU 4685 Prince and Princess(二分匹配+强联通分量)
题意:婚配问题,但是题目并不要求输出最大匹配值,而是让我们输出,一个王子可以与哪些王妃婚配而不影响最大匹配值. 解决办法:先求一次最大匹配,如果有两个已经匹配的王妃,喜欢她们两个的有两个或者以上相同的 ...
- hdu 4685 Prince and Princess(匈牙利算法 连通分量)
看了别人的题解.须要用到匈牙利算法的强连通算法 #include<cstdio> #include<algorithm> #include<vector> #pra ...
- HDU 3861 The King’s Problem 强连通分量 最小路径覆盖
先找出强连通分量缩点,然后就是最小路径覆盖. 构造一个二分图,把每个点\(i\)拆成两个点\(X_i,Y_i\). 对于原图中的边\(u \to v\),在二分图添加一条边\(X_u \to Y_v\ ...
- HDU4685 Prince and Princess【强连通】
题意: 有n个王子和m个公主,每个王子都会喜欢若干个公主,也就是王子只跟自己喜欢的公主结婚,公主就比较悲惨, 跟谁结婚都行.然后输出王子可能的结婚对象,必须保证王子与任意这些对象中的一个结婚,都不会影 ...
- hdu 4685(强连通分量+二分图)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685 题意:n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能 ...
- hdu 4685(强连通分量+二分图的完美匹配)
传送门:Problem 4685 https://www.cnblogs.com/violet-acmer/p/9739990.html 参考资料: [1]:二分图的最大匹配.完美匹配和匈牙利算法 [ ...
随机推荐
- IIS WMI Provider
section contains information about the classes that are implemented by the IIS WMI provider in the M ...
- 0x01第一个汇编程序
;将由text db 10,20,30,40定义的4个数相加,并输出其和. .386 ;指明指令集 .model flat,stdcall ;平坦模式,函数右边的参数先入栈 option cas ...
- windows鼠标消息处理与键盘模拟函数
1.鼠标坐标问题 BOOL GetWindowRect( HWND hWnd, LPRECT lpRect ); RECT x;//定义一个二维数组x ::GetWindowRect(hwn ...
- Jquery-------获取网页参数
看如下代码: function getURLParameter(name) { return decodeURI( (RegExp(name + '=' + '(.+?)(&|$)').exe ...
- android 开发:讯飞的离线命令识别器官方demo使用及demo下载
场景:使用本地构建语法,离线识别命令词. 修改文件AsrDemo.java mLocalGrammar 修改为你自己的语法 mAsr.setParameter(SpeechConstant.GRAM ...
- angular事件代理
在angular中,是不支持事件代理的,有些时候,我们需要处理比较多的数据,尤其是一些列表的时候,可能会很多,如果给每一项都加事件的话,注定慢很多,为了解决这个事情,因此需要一个做事件代理的direc ...
- Codeforces Beta Round #10 D. LCIS
题目链接: http://www.codeforces.com/contest/10/problem/D D. LCIS time limit per test:1 secondmemory limi ...
- ExtJS4.2学习(21)动态菜单与表格数据展示操作总结篇2
运行效果: 此文介绍了根据操作左侧菜单在右面板展示相应内容. 一.主页 先看一下跳转主页的方式:由在webapp根目录下的index.jsp跳转至demo的index.jsp 下面是demo的inde ...
- 【树形DP/搜索】BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会
1827: [Usaco2010 Mar]gather 奶牛大集会 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 793 Solved: 354[Sub ...
- 【BZOJ】【3295】【CQOI2011】动态逆序对
树套树 Orz zyf神犇 时光倒流……逆序处理,将删点改为加点,动态维护序列. 由于是动态,要加点,所以用树状数组:同时又需要求序列中求比当前元素大/小的元素个数,所以要用平衡树. 所以方法就是在树 ...