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

  解决办法:先求一次最大匹配,如果有两个已经匹配的王妃,喜欢她们两个的有两个或者以上相同的王子,那她们两个是可以交换的,对于前面的王子来说,他与这两个王妃中的任何一个匹配都不会影响最大匹配值,因为总有人把位置补上。那什么样的王妃才是可以交换的王妃呢?我们在这个王子已经匹配的王妃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. Gentoo/Funtoo USE标记介绍

    Gentoo/Funtoo USE标记 USE的简单理解如下:一个软件不只包含软件本身,还包括其组件,如,文档,插件,GUI支持等.USE就是用来标记是否要安装软件的同时安装这些组件. 声明USE标记 ...

  2. wpf 透明效果 需要DwmApi.dll文件,然后定义一个函数去画Aero区域,从而实现整个窗口的Aero化。

    private void ExtendAeroGlass(Window window) { try { // 为WPF程序获取窗口句柄 IntPtr mainWindowPtr = new Windo ...

  3. Objective-C中关于请求返回NSData数据解析成NSDictionary或NSArray的方法

    1.如果后台返回的是字典或数组的data型,直接使用以下方法转换: { // Data 转成 字典 其中responseObject为返回的data数据 NSDictionary *resultDic ...

  4. javascript中onSubmit="return xxx()"的问题

    javascript中onSubmit="return xxx()"刚开始我是想不通为什么要加return在里面呢,后来想想onSubmit="flase"就不 ...

  5. C++ socket programming in Linux

    Server.c #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #includ ...

  6. selinux策略开发

    所用软件: 1.setools -->seaudit  读取日志以确定所需权限 2.Reference Policy  -->  https://github.com/TresysTech ...

  7. RSA 公私钥 互换问题

    关于 RSA,我的理解是: 按定义的话,公私钥是可以互换的 问题是常见的实现里面,保存“私钥”的那个数据结构或者文件,里面除了私钥所必需的那一对数之外,还有额外的信息(足以算出公钥来),所以绝对不能把 ...

  8. ios UIApplocation 中APP启动方式

    iOS app启动的方式有哪些: 自己启动(用户手动点击启动) urlscheme启动(关于urlScheme的详解)http://www.cnblogs.com/sunfuyou/p/6183064 ...

  9. hdu_5221_Occupation(树剖)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5221 题意:给你一棵树,每个节点有一定的值,有三种操作: 1 x y 表示占领树上x-y的所有节点,2 ...

  10. centos装openoffice

    一.安装openOffice1.使用tar -xzvf OOo_3.2.0_LinuxIntel_install_wJRE_en-US.tar.gz解压缩后,会得到OOO320_m12_native_ ...