hdu 4685(强连通分量+二分图)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685
题意:n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能的结婚对象,
必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了。
分析:这题是poj 1904的加强版,poj 1904的王子和公主数是相等的,这里可以不等,且poj 1904给出了一个初始完美匹配,但是这题就要自己求。
所以只要求出完美匹配之后,就和poj 1904的做法就完全相同了,这里就不在赘述了,可以参考:http://www.cnblogs.com/frog112111/p/3384261.html
那么怎么求出完美匹配呢?一开始我用多重匹配的匈牙利算法来做,但是怎么做都不对.......看了题解才恍然大悟=_=
先说几个坑,这题有点奇怪,就是所有王子都可以争着和同一个公主结婚,只要该王子喜欢该公主,感觉公主有点悲哀呀........
比如:2 2
1 1
1 1
输出的答案是:1 1 而不是 1 1
1 1 0
这里就是和poj 1904有点不一样的地方,坑了我好久.........
求完美匹配:
先对原图用匈牙利算法做一遍二分图匹配,但是还有可能剩余一些人还没匹配,只要虚拟出一些节点来匹配剩余的点就行了
假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。
假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主
这样就构成完美匹配了,接下来就是和poj 1904一样了。
注意:虽然n和m才500,但是数组要开到2000才能过,可能是剩余太多顶点没匹配,所以要虚拟出比较多的顶点吧,我只开到1500,wa到死=_=
还有就是一些细节没处理好也贡献了好多wa,做了一天.........快奔溃了,最后参考别人的代码改来改去才AC,好艰辛,不过最终能过也算安慰了
果然想问题还是不够周全,不够细心
大三了都,哎,弱成一坨翔了~
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
const int M=+;
struct EDGE{
int v,next;
}edge[M];
int first[N],low[N],dfn[N],sta[M],belong[N];
int ans[N],match[N],flag[N];
bool instack[N],vis[N];
int n,m,g,cnt,top,scc,maxn;
int Scan() //输入外挂
{
int res=,ch,flag=;
if((ch=getchar())=='-')
flag=;
else if(ch>=''&&ch<='')
res=ch-'';
while((ch=getchar())>=''&&ch<='')
res=res*+ch-'';
return flag?-res:res;
}
void Out(int a) //输出外挂
{
if(a>)
Out(a/);
putchar(a%+'');
}
void AddEdge(int u,int v)
{
edge[g].v=v;
edge[g].next=first[u];
first[u]=g++;
}
int min(int a,int b)
{
return a<b?a:b;
}
int max(int a,int b)
{
return a>b?a:b;
}
void init()
{
g=cnt=top=scc=;
memset(first,-,sizeof(first));
memset(dfn,,sizeof(dfn));
memset(instack,false,sizeof(instack));
memset(flag,,sizeof(flag));
//scanf("%d%d",&n,&m);
n=Scan();
m=Scan();
maxn=max(n,m); //王子和公主数可能不同,为了建图方便去较大者,王子编号1--maxn,公主编号maxn+1--2*maxn
}
bool dfs(int u)
{
int i,v;
for(i=first[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(!vis[v])
{
vis[v]=true;
if(match[v]==||dfs(match[v]))
{
match[v]=u;
flag[u]=v;
return true;
}
}
}
return false;
}
void xiong() //二分匹配
{
int i;
memset(match,,sizeof(match));
for(i=;i<=maxn;i++)
{
memset(vis,false,sizeof(vis));
dfs(i);
}
}
void Tarjan(int u) //求强连通分量
{
int i,v;
low[u]=dfn[u]=++cnt;
sta[++top]=u;
instack[u]=true;
for(i=first[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(!dfn[v])
{
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
scc++;
while()
{
v=sta[top--];
instack[v]=false;
belong[v]=scc;
if(u==v)
break;
}
}
}
void build()
{
int i,k,v,j;
for(i=;i<=n;i++)
{
// scanf("%d",&k);
k=Scan();
while(k--)
{
// scanf("%d",&v);
v=Scan();
AddEdge(i,v+maxn); //王子和喜欢的公主之间连边
}
} xiong(); //做一次二分匹配 int all=*maxn;
for(i=;i<=maxn;i++) //为剩余王子匹配虚拟公主
{
if(!flag[i])
{
all++;
for(j=;j<=maxn;j++) //所有王子都喜欢该虚拟公主
AddEdge(j,all);
match[all]=i;
flag[i]=all;
}
} for(i=maxn+;i<=*maxn;i++) //为剩余公主匹配虚拟王子
{
if(!match[i])
{
all++;
for(j=maxn+;j<=*maxn;j++) //该虚拟王子喜欢所有公主
AddEdge(all,j);
flag[all]=i;
match[i]=all;
}
}
for(i=;i<=all;i++) //所有与王子匹配的公主建一条边连向王子
{
if(flag[i])
AddEdge(flag[i],i);
}
}
void solve()
{
int i,u,v;
for(i=;i<=maxn;i++) //求强连通分量
if(!dfn[i])
Tarjan(i); for(u=;u<=n;u++) //枚举所有王子
{
int count=;
for(i=first[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(belong[u]==belong[v]) //王子与公主同在一个强连通分量
{
if(v-maxn>m)
continue;
ans[count++]=v-maxn;
}
}
sort(ans,ans+count);
// printf("%d",count);
Out(count);
for(i=;i<count;i++) //输出
{
//printf(" %d",ans[i]);
putchar(' ');
Out(ans[i]);
}
// printf("\n");
putchar('\n');
}
}
int main()
{
int t,cas;;
// scanf("%d",&t);
t=Scan();
for(cas=;cas<=t;cas++)
{
init();
build();
printf("Case #%d:\n",cas);
solve();
}
return ;
}
hdu 4685(强连通分量+二分图)的更多相关文章
- hdu 4685(强连通分量+二分图的完美匹配)
传送门:Problem 4685 https://www.cnblogs.com/violet-acmer/p/9739990.html 参考资料: [1]:二分图的最大匹配.完美匹配和匈牙利算法 [ ...
- HDU 3072 (强连通分量)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3072 题目大意:为一个有向连通图加边.使得整个图全连通,有重边出现. 解题思路: 先用Tarjan把 ...
- UVa 12167 & HDU 2767 强连通分量 Proving Equivalences
题意:给出一个有向图,问最少添加几条有向边使得原图强连通. 解法:求出SCC后缩点,统计一下出度为0的点和入度为0的点,二者取最大值就是答案. 还有个特殊情况就是本身就是强连通的话,答案就是0. #i ...
- HDU4865 Prince and Princess 强连通分量+二分图判定
这个题就是建图费点劲,别的和我上一篇博客一样 然后,参考思路请戳这里http://www.cnblogs.com/wally/archive/2013/09/12/3317883.html 补充:这个 ...
- POJ 1904 King's Quest 强连通分量+二分图增广判定
http://www.cnblogs.com/zxndgv/archive/2011/08/06/2129333.html 这位神说的很好 #include <iostream> #inc ...
- HDU 4685 Prince and Princess(二分图+强连通分量)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685 题意:给出n个王子和m个公主.每个王子有一些自己喜欢的公主可以匹配.设最大匹配为M.那么对于每个 ...
- hdu 4685 二分匹配+强连通分量
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 题解: 这一题是poj 1904的加强版,poj 1904王子和公主的人数是一样多的,并且给出 ...
- hdu 4685(匹配+强连通分量)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685 思路:想了好久,终于想明白了,懒得写了,直接copy大牛的思路了,写的非常好! 做法是先求一次最 ...
- 【HDU3861 强连通分量缩点+二分图最小路径覆盖】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题目大意:一个有向图,让你按规则划分区域,要求划分的区域数最少. 规则如下:1.有边u到v以及有 ...
随机推荐
- linux 下 mysql-5.5.8 安装
安装环境:Linux服务器CentOS 5.5 安装版本:mysql-5.5.8.tar.gz 1.安装 cmake 编译器. 1).下载cmake #cd /usr/local/src #wget ...
- BZOJ2125 最短路 圆方树、倍增
传送门 对仙人掌建立圆方树,然后对边定权 对于圆点和圆点之间的边,是原来仙人掌上的桥,边权保持不变 对于圆点和方点之间的边,将圆方树看做以一个圆点为根的有根树之后,一个方点的父亲一定是一个圆点.对于这 ...
- CF1097D Makoto and a Blackboard 积性函数、概率期望、DP
传送门 比赛秒写完ABC结果不会D--最后C还fst了qwq 首先可以想到一个约数个数\(^2\)乘上\(K\)的暴力DP,但是显然会被卡 在\(10^{15}\)范围内因数最多的数是\(978217 ...
- CF28D Don't fear, DravDe is kind 背包
题目传送门:http://codeforces.com/problemset/problem/28/D 题意:给你$N$个物品,每个物品有其价格$P_i$,之前必须要买的物品价格和$L_i$,之后必须 ...
- asp.net网站,在没有项目源码情况下的扩展
如果在没有源码的情况下,要扩展asp.net网站,可以自己新增一个类库项目,在里面添加需要扩展的类,代码如下: using System; using System.Collections.Gener ...
- 并行管理工具——pdsh
1. pdsh安装2. pdsh常规使用2.1 pdsh2.2 pdcp 并行管理的方式有很多种: 命令行 一般是for循环 脚本 一般是expect+ssh等自编辑脚本 工具 pssh,pdsh,m ...
- [T-ARA][남주긴 아까워][给别人可惜了]
歌词来源:http://music.163.com/#/song?id=29343992 作曲 : 二段横踢/Radio Galaxi [作曲 : 二段横踢/Radio Galaxi] 作词 : 二段 ...
- 利用阿里云的源yum方式安装Mongodb
今天在线上服务器上安装MongoDB,从Mongo官网直接下载链接,结果在下载时发觉速度慢的可怜.迫于无奈,只能找国内的镜像下载.这里选择阿里云的源进行安装,记录如下: 1)在/etc/yum.rep ...
- Visual Studio2013安装过程以及单元测试
一.安装环境 操作系统版本:Windows10家庭中文版64位 CPU:i5-4200u 1.60GHz 硬盘内存:750G 二.安装版本 Visual Studio2013 三.安装过程 Visu ...
- Linux内核分析— —进程的切换和系统的一般执行过程
进程调度的时机 linux进程调度是基于分时和优先级的 中断处理过程(包括时钟中断.I/O中断.系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用s ...