题意:婚配问题,但是题目并不要求输出最大匹配值,而是让我们输出,一个王子可以与哪些王妃婚配而不影响最大匹配值。

  解决办法:先求一次最大匹配,如果有两个已经匹配的王妃,喜欢她们两个的有两个或者以上相同的王子,那她们两个是可以交换的,对于前面的王子来说,他与这两个王妃中的任何一个匹配都不会影响最大匹配值,因为总有人把位置补上。那什么样的王妃才是可以交换的王妃呢?我们在这个王子已经匹配的王妃match[i]与他喜欢的王妃v连一条有向边,那样处在一个强联通分量的两个王妃就是可以相互交换的。

  下面处理没有匹配的王妃的情况,假设最大匹配值为res,那我们在左边加上m-res个虚拟点,右边加上n-res个虚拟点,左边的虚拟点喜欢所有的王妃,右边的虚拟点被所有的王子喜欢,再求一次最大匹配,然后把边连上。这种方法很巧妙,因为一个没有匹配的王妃,所有的王子都可以跟她匹配而不影响最大值,把她加到强联通分量中的方法就是加这种虚拟点。

  注意:我们在联通分量里建的边还是挺多的,我用的maxn*2就WA了,后来干脆改成maxn*maxn,就AC了。

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<cstring>
using namespace std;
#define maxn 2020
int map1[maxn][maxn];
int link[maxn],vis[maxn];
struct Edge
{
int to,nxt;
} edge[maxn*maxn];
int head[maxn],low[maxn],dfn[maxn],id[maxn];
int all,tot,scc;
bool hungry(int u,int m)
{
for(int i = ; i <= m; i++)
{
if(map1[u][i] && !vis[i])
{
vis[i] = ;
if(link[i]==- || hungry(link[i],m))
{
link[i] = u;
return true;
}
}
}
return false;
}
int slove(int n,int m)
{
memset(link,-,sizeof(link));
int ans = ;
for(int i = ; i <= n; i++)
{
memset(vis,,sizeof(vis));
if(hungry(i,m)) ans++;
}
return ans;
}
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].nxt = head[u];
head[u] = tot++;
}
stack<int> s;
void init()
{
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(id,,sizeof(id));
all = ;
tot = ;
scc = ;
memset(head,-,sizeof(head));
while(!s.empty()) s.pop();
}
void tarjan(int u)
{
low[u] = dfn[u] = ++all;
s.push(u);
for(int i = head[u]; i != -; i = edge[i].nxt)
{
int v = edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(!id[v]) low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u])
{
scc++;
int num;
while(!s.empty())
{
num = s.top();
s.pop();
id[num] = scc;
if(num == u) break;
}
}
}
int main()
{
int t,a,b,k,n,m,ca = ;
scanf("%d",&t);
while(t--)
{
memset(map1,,sizeof(map1));
scanf("%d%d",&n,&m);
for(int i = ; i <= n; i++)
{
scanf("%d",&k);
while(k--)
{
scanf("%d",&a);
map1[i][a] = ;
}
}
int match_num;
match_num = slove(n,m);
int newn,newm;
newn = newm = n+m-match_num;
for(int i = n+; i <= newn; i++)
{
for(int j = ; j <= newm; j++)
{
map1[i][j] = ;
}
}
for(int i = ; i <= newn; i++)
{
for(int j = m+; j <= newm; j++)
{
map1[i][j] = ;
}
}
match_num = slove(newn,newm);
int match[maxn];
memset(match,-,sizeof(match));
for(int i = ; i <= newm; i++)
{
match[link[i]] = i;
}
init();
for(int i = ; i <= newn; i++)
{
for(int j = ; j <= newm; j++)
{
if(map1[i][j] && match[i] != j)
{
addedge(match[i],j);
}
}
}
for(int i = ; i <= newm; i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
vector<int>ve;
printf("Case #%d:\n",++ca);
for(int i = ;i <= n;i++)
{
ve.clear();
//printf("match[%d] = %d\n",i,match[i]);
for(int j = ;j <= m;j++)
{
//printf("id[%d] = %d\n",j,id[j]);
if(map1[i][j] && id[j] == id[match[i]])
{
ve.push_back(j);
}
}
int len = ve.size();
printf("%d",len);
for(int j = ;j < len;j++)
{
printf(" %d",ve[j]);
}
printf("\n");
}
}
return ;
}

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://acm.hdu.edu.cn/showproblem.php?pid=4685 题意:给出n个王子和m个公主.每个王子有一些自己喜欢的公主可以匹配.设最大匹配为M.那么对于每个 ...

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

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

  5. HDU 4685 Prince and Princess

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

  6. HDU 1269 迷宫城堡 【强联通分量(模版题)】

    知识讲解: 在代码里我们是围绕 low 和 dfn 来进行DFS,所以我们务必明白 low 和 dfn 是干什么的? 有什么用,这样才能掌握他.   1.  dfn[]  遍历到这个点的时间 2.   ...

  7. HDU 5934 强联通分量

    Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  8. 【强联通图 | 强联通分量】HDU 1269 迷宫城堡 【Kosaraju或Tarjan算法】

      为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明 ...

  9. Kosaraju算法---强联通分量

    1.基础知识 所需结构:原图.反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边).标记数组(标记是否遍历过).一个栈(或记录顶点离开时间的数组).      算法描叙: :对 ...

随机推荐

  1. LeetCode OJ 31. Next Permutation

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...

  2. Linode开通新加坡机房:vps速度快,价格不变!

    vps服务商linode终于开通了新加坡机房中心,这是linode全球第7个机房,满足日益增长的东南亚市场需求.印度.中国.澳大利亚及周边国家都有很好的用户体验. linode新加坡机房采用思科Cis ...

  3. NOIP2011-普及组复赛模拟试题-第一题-NBA总冠军

    题目背景 Background 一年两度的期末考要到来了!!  题目描述 Description   又要到考试了,Ljw决定放松一下,就打开电视,看见了篮球赛,他立即想到了每年的NBA总冠军队伍.由 ...

  4. Dash:程序员的好帮手

    Dash 关于Dash是什么.有哪些功能以及该怎么使用,我想直接引用咖啡 生活 美女蛇,这位小伙伴整理的很详细,我这里只说一下Dash的破解方法. 破解 破解补丁下载:Dash3.x_Cracked ...

  5. 为什么yslow用不了

    因为yslow暂时不支持 Firefox 36以上版本.建议您可以使用它的书签版.访问这里 http://yslow.org/mobile/把页面最后的那个 Desktop Bookmarklet I ...

  6. C语言指针强制转化的应用

    指针类型强制转化在kernel设计中非常常见,这里记录两个非常有意思的用法: 1.对地址进行运算.任何虚拟地址都表示成void *va  = (void *) 100, *(va + 1) ==101 ...

  7. [转]html 移动互联网终端的javascript touch事件,touchstart, touchend, touchmove

    前言 如果我们允许用户在页面上用类似桌面浏览器鼠标手势的方式来控制WEB APP,这个页面上肯定是有很多可点击区域的,如果用户触摸到了那些可点击区域怎么办呢??诸如智能手机和平板电脑一类的移动设备通常 ...

  8. HDU3371--Connect the Cities(最小生成树)

    Problem Description In 2100, since the sea level rise, most of the cities disappear. Though some sur ...

  9. android基础知识点复习之短信发送

    界面布局: activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/an ...

  10. ios设置textField只能输入数字用于电话号码

    首先在.xib中将UITextField的Keyboard设置为Number Pad,但是使用时键盘会切回别的键盘无法对内容进行校验.通过神奇的百度我知道了通过以下方法可以解决这样的问题: 首先让.x ...