您的位置:首页 > 其它

【hdu】4685 Prince and Princess【二分匹配+tarjan】

2016-08-06 13:27 357 查看
题意:有n个王子,m个公主,每个王子有他自己喜欢的公主们,问一个王子可以匹配的公主有哪些,要求一个王子匹配一个公主后,总的可匹配数不能减少,也就是不能让别的王子的本来可以有老婆的,现在没了。

题解:题意和poj1904集合一样,只不过那题给出了完美匹配,且王子与公主都是n个,这题又加了限制,是poj1904的加强版,可以先试试那题再来做这题后好理解很多,这是poj1904的题解 http://blog.csdn.net/a709743744/article/details/52133778

现在我们在上述题解的情况下继续讲这题怎么做,我们把这题尽量转换成poj1904的形式,我们先对题目给出的条件求一次二分匹配,

假设匹配数是cnt,

对于未匹配的n-cnt个王子,我们虚拟出n-cnt个公主和他匹配,并让所有真实王子都喜欢这个虚拟公主

对于未匹配的m-cnt个公主,我们虚拟出m-cnt个王子和她匹配,并让虚拟王子喜欢所有的真实公主

这样王子和公主都有n+m-cnt个,问题就完全转换成了poj1904,然后我们就按poj1904求一遍强连通,记得最后别输出虚拟公主即可

#include<queue>
#include<vector>
#include<cstdio>//先用强连通缩点来化简图,然后在图上做拓扑排序,如果排序过程中,出现1个以上的点入度同时为0时,那么就不满足条件。
#include<cstring>
#include<algorithm>
#define PB push_back
#define MP make_pair
using namespace std;
const int N=4010;
const int inf=0x3f3f3f3f;
int dfn
,low
,instack
,belong
,S
;
int index,scc,shead;
vector<int>G
;
vector<pair<int,int> >E
;
void dfs(int u)
{
dfn[u]=low[u]=++index;
S[shead++]=u;
instack[u]=true;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(!dfn[v]){
dfs(v);
low[u]=min(low[v],low[u]);
}else if(instack[v])
low[u]=min(dfn[v],low[u]);
}
if(low[u]==dfn[u]){
scc++;
while(1){
int tmp=S[--shead];
belong[tmp]=scc;
instack[tmp]=false;
if(tmp==u)break;
}
}
}
void tarjan(int n)
{
index=scc=shead=0;
memset(dfn,0,sizeof(dfn));
memset(instack,false,sizeof(instack));
for(int i=1;i<=n;i++)if(!dfn[i])dfs(i);
}
int ans
,lx
,ly
,used
,n,m;
bool Dfs(int u)
{
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(!used[v]){
used[v]=true;
if(ly[v]==-1||Dfs(ly[v])){
ly[v]=u;
lx[u]=v;
return true;
}
}
}
return false;
}
int hungry(int n)
{
int res=0;
memset(lx,-1,sizeof(lx));
memset(ly,-1,sizeof(ly));
for(int i=1;i<=n;i++){
memset(used,0,sizeof(used));
if(Dfs(i))res++;
}
return res;
}
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=(n+m)*2;i++)G[i].clear();
for(int i=1;i<=n;i++){
int x,y;
scanf("%d",&x);
while(x--){
scanf("%d",&y);
G[i].PB(n+y);
}
}
hungry(n);
int all=n+m;
for(int i=1;i<=n;i++)if(lx[i]==-1){//新增妹子
all++;
lx[i]=all;
ly[all]=i;
for(int j=1;j<=n;j++)G[j].PB(all);
}
for(int j=1;j<=m;j++)if(ly[j+n]==-1){//新增王子
all++;
lx[all]=j+n;
ly[j+n]=all;
for(int j=1;j<=m;j++)G[all].PB(j+n);
}
for(int i=1;i<=all;i++)
if(lx[i]!=-1)G[lx[i]].PB(i);
tarjan(all);
printf("Case #%d:\n",++kase);
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=0;j<G[i].size();j++){
int v=G[i][j];
if(belong[i]==belong[v]){
if(v-n<=m)ans[cnt++]=v-n;
}
}
sort(ans,ans+cnt);
printf("%d",cnt);
for(int j=0;j<cnt;j++){
printf(" %d",ans[j]);
}
printf("\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: